【问题标题】:React-Redux: Actions must be plain objects. Use custom middleware for async actionsReact-Redux:动作必须是普通对象。使用自定义中间件进行异步操作
【发布时间】:2018-03-27 17:07:57
【问题描述】:

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

我想在每个帖子中添加 cmets。因此,当运行获取帖子时,我想为所有帖子调用获取评论 API。

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

【问题讨论】:

    标签: reactjs react-redux


    【解决方案1】:

    这个错误主要发生在你正在调度一个动作并且你的动作没有返回一个对象时。例如这里是一个增量函数,当单击增量按钮时,我用它来增加数值。 const increment = () => type: INCREMENT 这是我的调度函数onClick={() => dispatch(increment)} 因为省略了括号 () 内部调度功能现在在您的终端中会出现相同的错误。调度函数需要一个对象而不是函数名的原因......

    【讨论】:

      【解决方案2】:

      箭头函数语法

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

      【讨论】:

        【解决方案3】:

        对我来说,解决方案是添加 redux-thunk 作为中间件,所以在我的商店配置文件中,我将 redux-thunk 作为中间件传递。

        在控制台内:

        import reducerData from './store-reducer';
        import {applyMiddleware, compose, createStore} from 'redux';
        import ReduxThunk from 'redux-thunk';
        
        const middlewares = [ReduxThunk];
        
        const store = createStore(
          reducerData,
          compose(applyMiddleware(...middlewares)),
        );
        export default store;
        

        【讨论】:

          【解决方案4】:

          您可能也像我一样忘记了在中间件数组中设置 getDefaultMiddleware()。无需进一步安装:

          export const store = configureStore({
            reducer: GlobalReducer,
            middleware: (getDefaultMiddleware) => [
              ...getDefaultMiddleware(),
              mainMiddleware,
            ],
          });
          

          【讨论】:

            【解决方案5】:

            就我而言,我只是想将一些值发送到服务器而不将它们保存到 redux 存储,所以我没有使用类型,也没有在最后调度任何东西。但我是用调度来调用这个动作的。所以我所要做的就是删除调度,因为它不是真正的动作。这只是一个函数。

            【讨论】:

              【解决方案6】:

              如果此代码正常工作并且这是一个新的迭代,请检查以确保您的变量以正确的顺序用于函数(这是我的错误)

              即 出现此错误的代码

              export const fetchProjects = newPage => (getState, dispatch) => NOPE
              
              export const fetchProjects = newPage => (dispatch, getState) => OK YEAH
              

              【讨论】:

              • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
              【解决方案7】:

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

              const [loading, setLoading] = useState(false)
              

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

              【讨论】:

                【解决方案8】:

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

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

                【讨论】:

                  【解决方案9】:

                  如果您正在使用 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)),
                            )
                  

                  【讨论】:

                    【解决方案10】:

                    变化:

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

                    到,

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

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

                    【讨论】:

                      【解决方案11】:

                      错误只是要求您在其间插入一个有助于处理异步操作的中间件。

                      你可以这样做:

                      npm i redux-thunk

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

                      现在,异步操作将在您的函数中运行。

                      【讨论】:

                      • 我将createSliceasyncThunk 一起使用,经过这么多问题和答案,您的答案奏效了。谢谢。
                      【解决方案12】:

                      动作定义

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

                      行动调度

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

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

                      【讨论】:

                        【解决方案13】:

                        我遇到了同样的问题,因为我错过了添加 composeEnhancers。设置完成后,您可以查看动作创建者。如果未设置,您也会收到此错误。

                        const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
                        
                        const store = createStore(
                          rootReducer,
                          composeEnhancers(applyMiddleware(thunk))
                        );
                        

                        【讨论】:

                          【解决方案14】:

                          对于像我这样可能已经放弃简单细节的未来寻求者,就我而言,我只是忘记用括号调用我的操作函数。

                          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 的问题无关,但我希望我能帮助遇到与我相同问题的人。

                          【讨论】:

                          • 谢谢。很容易错过。没有做任何异步的事情,所以我知道这是我错过的简单事情!
                          • 哦,谢谢。我犯了同样的错误:)
                          【解决方案15】:

                          您必须在异步请求结束后进行调度。

                          这可行:

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

                          【讨论】:

                          • 下面会提到,但你需要有 redux-thunk 中间件才能工作
                          • @sadiq 为什么必须调度一个动作?我没有定义为“异步调度”的异步操作遇到了同样的问题,尽管我不想向商店发送任何东西。
                          【解决方案16】:

                          使用箭头函数可以提高代码的可读性。 不需要在API.fetchComments 中返回任何内容,当请求完成时,API 调用是异步的,then 会得到响应,你只需要dispatch 类型和数据。

                          下面的代码通过使用箭头函数来完成同样的工作。

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

                          【讨论】:

                            【解决方案17】:

                            您不能在没有中间件的情况下在操作中使用 fetch。动作必须是普通对象。您可以使用 redux-thunk 或 redux-saga 之类的中间件来执行 fetch,然后调度另一个操作。

                            这是一个使用 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));
                                  })
                              }
                            }
                            

                            【讨论】:

                            • 对不起,我以为你没有使用中间件。 @sadiq 提到它是那里的调度问题。
                            猜你喜欢
                            • 2018-11-12
                            • 2018-01-31
                            • 2019-01-05
                            • 2019-06-17
                            • 2018-09-14
                            • 2020-01-06
                            • 2021-11-04
                            • 2020-04-18
                            • 1970-01-01
                            相关资源
                            最近更新 更多