Как я могу изменить этот вызов ASYNC в моем компоненте реагирования, чтобы сделать его более читабельным? - PullRequest
0 голосов
/ 26 мая 2019

Я хочу, чтобы мой компонент извлекал массив объектов с сервера. Каждый объект - это сообщение с автором, телом и датой. Затем я хочу отобразить эти сообщения в моем компоненте реакции.

Мой компонент реагирования в настоящее время получает данные с сервера перед монтированием. Затем он сохранит этот список сообщений в избыточном состоянии. |

Я уверен, что есть лучший способ написания этого кода. 1. Могу ли я разместить запрос на выборку в файле Action или Reducer? 2. Могу ли я написать функцию в компоненте для выполнения асинхронного вызова?

import React, { Component } from 'react';
import Message from '../components/message.jsx';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
// Actions
import { fetchMessages } from '../actions/actions_index.js';

class MessageList extends Component {
  constructor(props) {
    super(props)
  }

  componentWillMount() {
    fetch('https://wagon-chat.herokuapp.com/general/messages')
        .then(response => response.json(),
          error => console.log('An error occured receiving messages', error))
        .then((data) => {
          this.props.fetchMessages(data.messages);
        });
  }

  render() {
    return (
      <div className="message-list">
        {this.props.messageList.map( (message, index) => { return <Message key={index} message={message}/> })}
      </div>
    )
  }
}

function mapStateToProps(state) {
  return {
    messageList: state.messageList
  }
}

function mapDispatchToProps(dispatch) {
  return bindActionCreators(
    { fetchMessages: fetchMessages },
    dispatch
  )
}

export default connect(mapStateToProps, mapDispatchToProps)(MessageList);

Ответы [ 3 ]

2 голосов
/ 26 мая 2019
  1. Можно ли разместить запрос на выборку в файле Action или Reducer?

Запрос на выборку должен быть помещен в создатель действия.Где извлеченные данные будут dispatched, чтобы затем уменьшить их, чтобы манипулировать данными, и, наконец, обновить хранилище, чтобы показать в пользовательском интерфейсе.Вот простой процесс для большинства приложений реагировать на избыточность.

Пользовательский интерфейс -> Создатель действий (запрос вызова, сага и т. Д.) -> редуктор -> магазин -> Пользовательский интерфейс

Могу ли я написать функцию в компоненте для выполнения асинхронного вызова?

Да, это следует назвать создатель действия , и вы можете увидеть actions.js ниже для получения дополнительной справки.

Я думаю, что вы можете смело следовать этому образцу, к которому применимо большинство учебных пособий.Я предполагаю, что все файлы, перечисленные здесь, находятся в одном каталоге.

constant.js

const MESSAGE_FETCH__SUCCESS = 'MESSAGE/FETCH__SUCCESS'
const MESSAGE_FETCH__ERROR = 'MESSAGE/FETCH__ERROR'
export {
  MESSAGE_FETCH__SUCCESS,
  MESSAGE_FETCH__ERROR
}

actions.js

import {
  MESSAGE_FETCH__SUCCESS,
  MESSAGE_FETCH__ERROR
} from './constant';

const fetchMessageError = () => ({
  type: MESSAGE_FETCH__ERROR
})

const fetchMessageSuccess = data => ({
  type: MESSAGE_FETCH__SUCCESS,
  payload: data
})

const fetchMessages = () => {
  const data = fetch(...);

  // if error 
  if (data.error)
    fetchMessageError();
  else fetchMessageSuccess(data.data);
}

export {
  fetchMessages
}

redurs.js

import {
  MESSAGE_FETCH__SUCCESS,
  MESSAGE_FETCH__ERROR
} from './constant';

const INIT_STATE = {
  messageList: []
}

export default function( state = INIT_STATE, action ) {
  switch(action.type) {
    case MESSAGE_FETCH__SUCCESS:
      return {
        ...state,
        messageList: action.payload
      }
    case MESSAGE_FETCH__ERROR:
      // Do whatever you want here for an error case
      return {
        ...state
      }
    default:
      return state;
  }
}

index.js

Прочитайте комментарий, который я отметил

import React, { Component } from 'react';
import Message from '../components/message.jsx';
import { connect } from 'react-redux';

// Actions
import { fetchMessages } from './actions';

class MessageList extends Component {
  /* If you don't do anything in the constructor, it's okay to remove calling `constructor(props)`
  */
  //constructor(props) {
  //    super(props)
  //}

  // I usually put this async call in `componentDidMount` method
  componentWillMount() {
    this.props.fetchMessage();
  }

  render() {
    return (
      <div className="message-list">
        {
          /* Each message should have an unique id so they can be used 
          for `key` index. Do not use `index` as an value to `key`. 
See this useful link for more reference: https://stackoverflow.com/questions/28329382/understanding-unique-keys-for-array-children-in-react-js
          */
          this.props.messageList.map( message => <Message key={message.id} message={message}/> )
        }
      </div>
    )
  }
}

function mapStateToProps(state) {
  return {
    messageList: state.messageList
  }
}

export default connect(mapStateToProps, {
  fetchMessages
})(MessageList);
1 голос
/ 26 мая 2019

Вы можете использовать redux-thunk в действии, называемом getMessages.

Итак: (функция с двойной стрелкой для возврата действия, см. Redux-thunk)

const getMessages = ()=>(dispatch, getState)=>{
    fetch('https://wagon-chat.herokuapp.com/general/messages')
    .then(response => response.json(),
      error => dispatch(['error', error]))
    .then((data) => {
      dispatch(data);
    })
}

Тогда вы успешно уменьшили свой компонент до:

componentWillMount(){
    this.props.getMessages()
}
0 голосов
/ 07 июня 2019

Я думаю, что @Duc_Hong ответил на вопрос.

И, на мой взгляд, я предлагаю использовать промежуточное программное обеспечение для побочных эффектов, чтобы сделать вызов AJAX более структурированным, чтобы мы могли обрабатывать более сложные сценарии (например, отменить запрос ajax, несколько запросов одновременно) и сделать его более проверяемый.

Вот фрагмент кода с использованием Redux Saga

// Actions.js

const FOO_FETCH_START = 'FOO\FETCH_START'
function action(type, payload={}) {
  return {type, payload};
}
export const startFetch = () => action{FOO_FETCH_START, payload);

// reducer.js

export const foo = (state = {status: 'loading'}, action) => {
  switch (action.type) {
  case FOO_FETCH_STARTED: {
    return _.assign({}, state, {status: 'start fetching', foo: null});
  }
  case FOO_FETCH_SUCCESS: {
    return _.assign({}, state, {status: 'success', foo: action.data});
  }
  ......
  }
};
  1. Можно ли разместить запрос на выборку в файле Action или Reducer?

// Saga.js, Я помещаю здесь вызов ajax (fetch, axios, что вы хотите) .

export function* fetchFoo() {
  const response = yield call(fetch, url);
  yield put({type: FOO_FETCH_SUCCESS, reponse.data});
}

// This function will be used in `rootSaga()`, it's a listener for the action FOO_FETCH_START
export function* fooSagas() {
  yield takeEvery(FOO_FETCH_START, fetchFoo);
}
  1. Могу ли я написать функцию в компоненте для выполнения асинхронного вызова?

// Реагировать на компонент, Я запускаю выборку созданием действия в componentDidMount

class Foo extends React.Component {
  componentDidMount() {
    this.props.startFetch();
  }
  render() {
    <div>
     {this.props.foo.data ? this.props.foo.data : 'Loading....'}
    <div>
  }
}
const mapStateToProps = (state) => ({foo: state.foo});
const mapDispatchToProps = { startFetch }
export default connect(mapStateToProps, mapDispatchToProps) (Foo);

// client.js, связывают саги, редуксы и компоненты React

const render = App => {
 const sagaMiddleware = createSagaMiddleware();
 const store = createStore(
    combinedReducers,
    initialState,
    composeEnhancers(applyMiddleware(sagaMiddleware))
  );
 store.runSaga(rootSaga);
 return ReactDOM.hydrate(
    <ReduxProvider store={store}>
      <BrowserRouter><AppContainer><App/></AppContainer></BrowserRouter>
    </ReduxProvider>,
    document.getElementById('root')
  );
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...