reactjs redux操作必须是普通对象

时间:2018-09-13 07:42:07

标签: javascript reactjs redux redux-saga

我遇到一个问题“ 操作必须是普通对象。将自定义中间件用于异步操作。

我正在使用带有此样板的reactjs(https://github.com/react-boilerplate/react-boilerplate/) 我浪费了1天的时间来解决此问题,但没有结果。我试图将获取请求移动到行动中(没有传奇),结果相同。

我的组件:

...
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循环中一样。我尝试在this.props.getData();componentDidMount中调用constructor,结果相同。

编辑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),
  };
}

1 个答案:

答案 0 :(得分:1)

你好@AND,欢迎来到stackoverflow!正如我在主要帖子的评论中提到的那样,您正在调度GENERATOR而不是对象上的对象

dispatch(saga());

这是一个可以帮助您的示例

在组件上导入要使用的操作,如下所示。

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

enter link description here

上了解有关bindActionCreators的更多信息

这将导入您在此处创建的所有导出的actionCreator。 我认为您不再需要successFetchingfailureFetching,因为您可以稍后在传奇中分派此操作

然后在您的mapDispatchToProps中,您要注册此动作创建者

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 latest NEWS_FETCH_LOADING actions that was dispatched and will call the获取新闻。

然后在您的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();
}