React-Redux:动作必须是普通对象。使用自定义中间件进行异步操作

时间:2017-10-16 08:23:43

标签: reactjs react-redux

未处理的拒绝(错误):操作必须是普通对象。使用自定义中间件进行异步操作。

详细信息:我想在每个帖子中添加评论。因此,当运行获取帖子时,我想为所有帖子调用fetch comment API。

这是我的代码:

export function bindComments(postId) {
  return API.fetchComments(postId).then(comments => {
    return {
      type: BIND_COMMENTS,
      comments,
      postId
    }
  })
}

由于

11 个答案:

答案 0 :(得分:24)

您必须在异步请求结束后发送。

这样可行:

export function bindComments(postId) {

 return function (dispatch){
   return API.fetchComments(postId).then(comments => {
   // dispatch
     dispatch( {
       type: BIND_COMMENTS,
       comments,
       postId
     })
   })
 }
}

答案 1 :(得分:11)

对于那些可能会像我一样遗漏简单细节的未来求职者,就我而言,我只是忘了用括号来调用我的动作函数。

actions.js:

export function addNewComponent() {
  return {
    type: ADD_NEW_COMPONENT,
  };
}

myComponent.js:

import React, { useEffect } from 'react';
import { addNewComponent } from '../../redux/actions';

  useEffect(() => {
    dispatch(refreshAllComponents); // <= Here was what I've missed.
  }, []);

我忘记了用()分派动作函数。因此,这样做解决了我的问题。

  useEffect(() => {
    dispatch(refreshAllComponents());
  }, []);

同样,这可能与OP的问题无关,但我希望我能帮助遇到与我的问题相同的人。

答案 2 :(得分:6)

错误只是要求您在中间插入一个中间件,以帮助处理异步操作。

您可以通过:

npm i redux-thunk

        Inside index.js

import thunk from "redux-thunk" 
        
...createStore(rootReducers, applyMiddleware(thunk));

现在,异步操作将在您的函数中起作用。

答案 3 :(得分:4)

变化:

export const <youractionName> = async (dispatch) => {}

到,

export const <youractionName> = () => async (dispatch) => {}

这解决了我的问题。错过了 '() =>'

答案 4 :(得分:2)

您不能在没有中间件的情况下使用fetch。动作必须是普通对象。你可以使用像redux-thunk或redux-saga这样的中间件来进行获取,然后再发送另一个动作。

以下是使用redux-thunk中间件的异步操作示例。

export function checkUserLoggedIn (authCode) {
 let url = `${loginUrl}validate?auth_code=${authCode}`;
  return dispatch => {
    return fetch(url,{
      method: 'GET',
      headers: {
        "Content-Type": "application/json"
      }
      }
    )
      .then((resp) => {
        let json = resp.json();
       if (resp.status >= 200 && resp.status < 300) {
          return json;
        } else {
          return json.then(Promise.reject.bind(Promise));
        }
      })
      .then(
        json => {
          if (json.result && (json.result.status === 'error')) {
            dispatch(errorOccurred(json.result));
            dispatch(logOut());
          }
          else{
            dispatch(verified(json.result));
          }
        }
      )
      .catch((error) => {
        dispatch(warningOccurred(error, url));
      })
  }
}

答案 5 :(得分:2)

充分利用Arrow函数,可以提高代码的可读性。 无需返回API.fetchComments中的任何内容,请求完成后then的Api调用将是异步的,您只需要dispatch的类型和数据即可。

下面的代码通过使用Arrow函数完成相同的工作。

export const bindComments = postId => {
  return dispatch => {
    API.fetchComments(postId).then(comments => {
      dispatch({
        type: BIND_COMMENTS,
        comments,
        postId
      });
    });
  };
};

答案 6 :(得分:2)

我遇到了与错过添加composeEnhancers相同的问题。设置完成后,您可以查看动作创建者。如果未同时设置,则会出现此错误。

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;

const store = createStore(
  rootReducer,
  composeEnhancers(applyMiddleware(thunk))
);

答案 7 :(得分:0)

动作定义

const selectSlice = () => {
  return {
    type: 'SELECT_SLICE'
  }
};

动作调度

store.dispatch({
  type:'SELECT_SLICE'
});

确保定义的动作的对象结构与分派的动作相同。就我而言,在调度操作时,没有将类型分配给属性type

答案 8 :(得分:0)

如果您正在使用 redux-observable,请检查您的操作是否返回了 observable。我遇到了这个问题,因为我使用的是地图而不是合并地图

// error
    export const myEpic = (action$: any) =>
      action$.pipe(
        ofType('...'),
        map((x => x.payload),
        map((x) => callAPi(x)),
      )
    
// success
        export const myEpic = (action$: any) =>
          action$.pipe(
            ofType('...'),
            map((x => x.payload),
            mergeMap((x) => callAPi(x)),
          )

答案 9 :(得分:0)

使用 redux-thunk,使用 redux 进行设置并创建这样的操作

export const actionName = (data) => dispatch => {
  dispatch({
    type:"ACTION_TYPE"
    payload:"my payload"
  })
}

答案 10 :(得分:0)

只是在这里分享我的案例。 我有一个 setLoading 操作,同时还有

const [loading, setLoading] = useState(false)

以上我没有删除。所以它基本上不是从 redux 调度 setLoading 而是从 useState 调度。删除/重命名它可以解决问题。