React / Redux: Ошибка: действия должны быть простыми объектами. Использовать пользовательское промежуточное ПО для асинхронных действий - PullRequest
0 голосов
/ 27 августа 2018

Вот код моего компонента UserHandler

import React, { Component } from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';

import * as actionCreators from '../../store/actions/actions';

class UserHandler extends Component {
  componentDidMount() {
    const { onInitUsers } = this.props;
    onInitUsers();
  }

  render() {
    // some code
    return (          
        {/* SOME JSX */}
    );
  }
}

const mapStateToProps = state => ({
  //    state to props mapping
});

const mapDispatchToProps = dispatch => ({
  onUserEdition: username => dispatch(actionCreators.editUser(username)),
  onUserSelection: username => dispatch(actionCreators.fetchSelectedUser(username)),
  onInitUsers: () => dispatch(actionCreators.initUsers()),
});

// PropTypes definition and defaultProps

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

И в моем actionCreators файле вот что я определил:

const initUsersStart = createAction(INIT_USERS_START);
const setUsers = createAction(SET_USERS, users => ({ users }));
const initUsersError = createAction(INIT_USERS_ERROR, error => ({ error }));


const initUsers = () => (dispatch) => {
  dispatch(initUsersStart());
  return axios.get('/users')
    .then(
      response => dispatch(setUsers(response.data)),
    )
    .catch(
      error => dispatch(initUsersError(error)),
    );
};

Когда я комментирую вызов onInitUsers(); в функции componentDidMount(), у меня больше нет ошибки. Я хочу понять, почему возникает эта ошибка.

Наконец, вот как я создаю свой store:

import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import { createStore, applyMiddleware } from 'redux';
import { Provider } from 'react-redux';
import thunk from 'redux-thunk';

import App from './App';
import registerServiceWorker from './registerServiceWorker';
import '../node_modules/bootstrap/dist/css/bootstrap.min.css';
import reducer from './store/reducers/reducers';

const store = createStore(
  reducer, /* preloadedState, */
  applyMiddleware(thunk),
  /* eslint-disable no-undef */ /* eslint-disable no-underscore-dangle */
  window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__(),
  /* eslint-enable */
);

// const store = createStore(reducer);

ReactDOM.render(
  <Provider store={store}>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </Provider>,
  /* eslint-disable no-undef */
  document.getElementById('root'),
  /* eslint-enable */
);
registerServiceWorker();

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

Ответы [ 3 ]

0 голосов
/ 27 августа 2018

Проблема в том, что вы отправляете действие с вызовом onInitUsers(), потому что оно внутри функции dispatch(). Если вы отправляете действие, вам нужно вернуть объект с ключом type и, необязательно, с полезной нагрузкой.

Что вам нужно, это bindActionCreators функция внутри вашего mapDispatchToProps вот так:

import { bindActionCreators } from "redux";

const mapDispatchToProps = dispatch => ({
  onUserEdition: username => dispatch(actionCreators.editUser(username)),
  onUserSelection: username => dispatch(actionCreators.fetchSelectedUser(username)),
  onInitUsers: bindActionCreators(actionCreators.initUsers, dispatch),
});

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


Редактировать: попробуйте изменить функцию onInitUser на следующее:

const initUsers = () => (dispatch) => {
  dispatch(initUsersStart());
  return dispatch({
            type: 'GET_USER',
            payload: axios.get('/users')
                .then(
                  response => dispatch(setUsers(response.data)),
                )
                .catch(
                  error => dispatch(initUsersError(error)),
                );
        });
};
0 голосов
/ 28 августа 2018

Это было опубликовано в списке проблем React-Redux , и я ответил на него там. Я напишу свое решение здесь для полноты.

Во-первых, коренная проблема заключается в том, что нечто, не являющееся объектом простого действия, достигает фактического хранилища. Вы можете поместить точку останова в функцию dispatch в исходном коде Redux, чтобы увидеть, каково действительное значение (или отредактировать копию Redux в папке node_modules вашего проекта, чтобы добавить некоторые записи).

На самом деле, я думаю, что вижу проблему. Настоящая проблема в том, что вы передаете два отдельных улучшения магазина в createStore. Один из них - улучшитель промежуточного программного обеспечения applyMiddleware, другой - расширение Redux DevTools. Вам нужно «собрать» их обоих вместе в комбинированный энхансер. На странице Настройка вашего магазина в документации Redux приведен пример того, как сделать это правильно с возможностью копирования.

Два других предложения:

Вместо написания mapDispatch функции вручную, вы можете использовать «стенографию объекта» и просто передать объект, полный создателей действий, непосредственно в connect. У вас уже есть объект, полный создателей действий из оператора import * as actionCreators, так что вы можете просто сделать: export default connect(mapState, actionCreators)(UserHandler). (При этом имена функций не совпадают с именами реквизитов, которые вы хотите, поэтому вам может потребоваться создать новый объект вместо {onUserSelection : actionCreators.fetchSelectedUser} и передать его вместо этого.)

Также у нас есть пакет redux-starter-kit , над которым мы работаем, который имеет единственную функцию для настройки вашего магазина и автоматически добавляет redux-thunk и расширение DevTools. Возможно, вы захотите попробовать это вместо того, чтобы настраивать магазин самостоятельно.

0 голосов
/ 27 августа 2018

Возвратите ваш вызов axios, таким образом, независимо от того, по какому пути идет ваша логика, объект возвращается в соответствии с требованиями Redux.

const initUsers = () => (dispatch) => {
  dispatch(initUsersStart());
  return axios.get('/users')
    .then(
      response => dispatch(setUsers(response.data)),
    )
    .catch(
      error => dispatch(initUsersError(error)),
    );
};

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

const store = createStore(
  reducer, /* preloadedState, */
  /* eslint-disable no-undef */ /* eslint-disable no-underscore-dangle */
  window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__(),
  /* eslint-enable */
  applyMiddleware(thunk),
);

Я проверил это с помощью redux v.4.0.0 и Reaction-redux v.5.0.7.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...