我遇到一个问题“ 操作必须是普通对象。将自定义中间件用于异步操作。”
我正在使用带有此样板的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),
};
}
答案 0 :(得分:1)
你好@AND,欢迎来到stackoverflow!正如我在主要帖子的评论中提到的那样,您正在调度GENERATOR而不是对象上的对象
dispatch(saga());
这是一个可以帮助您的示例
在组件上导入要使用的操作,如下所示。
import * actionCreators from './actions';
import { bindActionCreators } from 'redux';
上了解有关bindActionCreators的更多信息
这将导入您在此处创建的所有导出的actionCreator。
我认为您不再需要successFetching
和failureFetching
,因为您可以稍后在传奇中分派此操作
然后在您的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);
您说的是您将等待请求的请求/服务的结果,这可能是一个承诺。
然后在这里,这就是为什么您不再需要函数successFetching
和failureFetching
的原因了,因为您可以这样做
yield put({type: NEWS_FETCH_SUCCESS, req});
您现在要做的最后一个重要步骤是在componentDidMount()
内调用actionCreator
像这样
componentDidMount() {
const { preFetching } = this.props;
preFetching();
}