reactjs redux 动作必须是普通对象

reactjs redux Actions must be plain objects

我有一个问题“操作必须是普通对象。使用自定义中间件进行异步操作。

我在这个样板中使用 reactjs (https://github.com/react-boilerplate/react-boilerplate/) 我浪费了 1 天的时间来解决这个问题,但没有结果。我正在尝试将获取请求移动到操作(没有 saga)并且结果相同。

我的组件:

...
import { compose } from 'redux';
import injectReducer from 'utils/injectReducer';
import injectSaga from 'utils/injectSaga';
import { successFetching } from './actions';
import reducer from './reducers';
import saga from './saga';

class NewsListPage extends React.PureComponent {

  componentDidMount() {
    const { dispatch } = this.props
    dispatch(saga())
  }

  ...
};

NewsListPage.propTypes = {
  isFetching: PropTypes.bool.isRequired,
  isSuccess: PropTypes.bool.isRequired,
  items: PropTypes.array.isRequired,
  dispatch: PropTypes.func.isRequired,
}

const selector = (state) => state;

const mapStateToProps = createSelector(
  selector,
  (isFetching, isSuccess, items) => ({ isFetching, isSuccess,items })
);

function mapDispatchToProps(dispatch) {
  return {
    dispatch,
  };
}
const withReducer = injectReducer({ key: 'NewsList', reducer });
const withSaga = injectSaga({ key: 'NewsList', saga });
const withConnect = connect(mapStateToProps, mapDispatchToProps);

export default compose(
    withReducer,
    withSaga,
    withConnect
  )(NewsListPage);

我的操作:

export const NEWS_FETCH_LOADING = 'NEWS_FETCH_LOADING';
export const NEWS_FETCH_FAILURE = 'NEWS_FETCH_FAILURE';
export const NEWS_FETCH_SUCCESS = 'NEWS_FETCH_SUCCESS';

export function preFetching() {
  return {
    type: NEWS_FETCH_LOADING,
  }
}

export function successFetching(json) {
  return {
    type: NEWS_FETCH_SUCCESS,
    payload: json
  }
}

export function failureFetching(error) {
  return {
    type: NEWS_FETCH_FAILURE,
    payload: error
  }
}

我的减速器:

...
import { NEWS_FETCH_LOADING, NEWS_FETCH_FAILURE, NEWS_FETCH_SUCCESS } from './actions'

const INITIAL_STATE = {
  isFetching: false,
  isSuccess: false,
  items: []
};

function NewsListReducer(state = INITIAL_STATE, action) {
  switch (action.type) {
    case NEWS_FETCH_LOADING:
    case NEWS_FETCH_FAILURE:
      return Object.assign({}, state, {
        isFetching: true,
        isSuccess: false
      })
    case NEWS_FETCH_SUCCESS:
      return Object.assign({}, state, {
        isFetching: false,
        isSuccess: true,
        items: action.payload,
      })
    default:
      return Object.assign({}, state)
  }
}

export const rootReducer = combineReducers({
  NewsListReducer
})
export default rootReducer

我的传奇:

import { call, put, select, takeLatest } from 'redux-saga/effects';
import {NEWS_FETCH_LOADING, NEWS_FETCH_FAILURE, NEWS_FETCH_SUCCESS, preFetching, successFetching, failureFetching} from './actions';
import request from 'utils/request';

export function* getNews() {
  const requestURL ='%MY_URL%';

  try {
    const req = yield call(request, requestURL);
    yield put(successFetching(req));
  } catch (err) {
    yield put(failureFetching(err));
  }
}

export default function* NewsListSaga() {
  yield takeLatest(NEWS_FETCH_SUCCESS, getNews);
}

编辑: @Alleo Indong,我尝试了你的建议并且几乎成功了。

我将组件 mapDispatchToProps 更改为

export function mapDispatchToProps(dispatch) {
  return {
    getData: () => dispatch(loadNews()),
  };
}

并为 actions.js

添加新功能
export function loadNews() {
  return {
    type: NEWS_FETCH_SUCCESS,
  }
}

但现在 ajax 每秒发送一次 就像在 while 循环中一样。我尝试在 componentDidMountconstructor 中调用 this.props.getData();,结果相同。

编辑 2 在我添加的组件中

import * as  actionCreators from './actions';
import { bindActionCreators } from 'redux';

在构造函数中我改变了

constructor(props) {
  super(props);

  const {dispatch} = this.props;

  this.boundActionCreators = bindActionCreators(actionCreators, dispatch)
}

但是这里 dispatch 是未定义的,在 componentDidMount 中也是如此。 并将 mapDispatchToProps 更改为

export function mapDispatchToProps(dispatch) {
  return {
    ...bindActionCreators(actionCreators, dispatch),
  };
}

你好@AND,欢迎来到 Whosebug!正如我在主 post 的评论中提到的,您正在调度一个 GENERATOR 而不是

上的一个对象

dispatch(saga());

这里有一个例子可以帮助你

在您的组件上导入您要像这样使用的操作。

import * actionCreators from './actions';
import { bindActionCreators } from 'redux';

在此处了解有关 bindActionCreators 的更多信息 enter link description here

这将导入您在那里创建的所有导出的 actionCreator。 在我看来,您不再需要 successFetchingfailureFetching,因为您可以稍后在您的 saga

中发送此操作

然后在您的 mapDispatchToProps 中注册此 actioncreator

function mapDispatchToProps(dispatch) {
    return {
        ...bindActionCreators(actionCreators, dispatch),
    };
}

那么关于你的故事,我也想在这里指出一些问题。 首先是你的函数

export default function* NewsListSaga() {
    yield takeLatest(NEWS_FETCH_SUCCESS, getNews);
}

实际上是我们所说的 watcher ,它会在某个动作被调度时监视它,在这个函数中你已经在 NEWS_FETCH_SUCCESS 之前等待 getNews 被调用了错了,因为你先做了 FETCHING 然后你才会知道它是失败还是成功所以是的这个函数应该是这样的

export default function* NewsListSaga() {
    yield takeLatest(NEWS_FETCH_LOADING, getNews);
}

这个简单意味着您将 take all the latestNEWS_FETCH_LOADINGactions that was dispatched and will call thegetNews`。

然后在你的getNews生成器函数上,你可以这样做

export function* getNews() {
    const requestURL ='%MY_URL%';

    try {
        const req = yield call(request, requestURL);
        yield put({type: NEWS_FETCH_SUCCESS, req});
    } catch (err) {
        yield put({type: NEWS_FETCH_FAILED, err});
    }
}

在这里

const req = yield call(request, requestURL);

你说你会等待你调用的请求/服务的结果,这可能是一个承诺。

然后在这里,这就是为什么你不再需要函数 successFetchingfailureFetching 的原因,因为你可以这样做 yield put({type: NEWS_FETCH_SUCCESS, req});

您现在必须做的最后一个重要步骤是在您的 componentDidMount()

中调用 actionCreator

像这样

componentDidMount() {
    const { preFetching } = this.props;
    preFetching();
}