Redux Thunk vs Redux 自定义中间件

Posted

技术标签:

【中文标题】Redux Thunk vs Redux 自定义中间件【英文标题】:Redux Thunk vs Redux custom Middleware 【发布时间】:2020-09-21 20:58:06 【问题描述】:

我是 redux 的新手。所以在阅读了很多教程之后。我明白了,redux 需要 redux thunk 通过返回另一个函数来调度异步操作。但是如果我在自定义中间件中调用 http 请求那么

    是否需要 redux thunk ? Redux 自定义中间件没有副作用吗?我的意思是不需要返回另一个函数。

如果我使用 redux thunk,那么我的动作创建器看起来像这样。这个我明白了

function incrementAsync() 
  return (dispatch) => 
    setTimeout(() => 
      // Yay! Can invoke sync or async actions with `dispatch`
      dispatch(increment());
    , 1000);
  ;

我对自定义中间件感到困惑。

https://blog.logrocket.com/managing-asynchronous-actions-in-redux-1bc7d28a00c6/

根据这个博客

const httpMiddleware = store => next => action => 
  if (action[HTTP_ACTION]) 
    const actionInfo = action[HTTP_ACTION];
    const fetchOptions = 
      method: actionInfo.verb,
      headers: actionInfo.headers,
      body: actionInfo.payload || null
    ;

    next(
      type: actionInfo.type + "_REQUESTED"
    );

    fetch(actionInfo.endpoint, fetchOptions)
      .then(response => response.json())
      .then(data => next(
        type: actionInfo.type + "_RECEIVED",
        payload: data
      ))
      .catch(error => next(
        type: actionInfo.type + "_FAILED",
        payload: error
     ));
   else 
    return next(action);
  

他们没有在动作中返回任何调度函数。我知道 store,next,action 是内部函数。

谁能帮我理解这件事? 谢谢。

【问题讨论】:

【参考方案1】:

All redux-thunk 是一个简单的 redux 中间件,用于检查您的操作是否为函数并相应地执行。您可以在 5 分钟内自行构建。

您可以看到它从 store 对象中解构 dispatchgetState,然后将它们作为参数调用您的操作。

看看它是source code。

因此,您的示例代码可能如下所示:

const httpMiddleware = store => next => action => 
  if (action[HTTP_ACTION]) 
    const actionInfo = action[HTTP_ACTION];
    const fetchOptions = 
      method: actionInfo.verb,
      headers: actionInfo.headers,
      body: actionInfo.payload || null
    ;

    store.dispatch(
      type: actionInfo.type + "_REQUESTED"
    );

    fetch(actionInfo.endpoint, fetchOptions)
      .then(response => response.json())
      .then(data => store.dispatch(
        type: actionInfo.type + "_RECEIVED",
        payload: data
      ))
      .catch(error => store.dispatch(
        type: actionInfo.type + "_FAILED",
        payload: error
     ));
   else 
    return next(action);
  

【讨论】:

@Sagi。感谢您的回答。即使我看到了源代码..如果我调用 axios 或在自定义中间件中获取,我可以直接调度操作本身而不是 next(actonType) 另外,如果我使用自定义中间件,则不需要使用 redux thunk。我正确吗? 是的,你是对的。看看我在答案中编辑的示例代码。 @sagi。感谢您的澄清。很明显,自定义中间件不需要 redux thunk。非常感谢【参考方案2】:

正如你按点列表询问的那样,我将按点列表回复:

如果我在自定义中间件中调用 http 请求,那么它是必需的吗 redux thunk ?

Redux thunk 本身就是一个中间件,如果您想要调度一个执行(例如)AJAX 调用的操作并根据该 AJAX 调用的结果调度两个不同的操作(如果它失败了一个),建议您使用它如果成功则返回一个。

Redux 自定义中间件没有副作用吗?我的意思是不需要返回另一个函数。

如果我的理解正确:中间件会简单地接受您调度的操作并将其传递给链,它会让您在将操作发送到减速器“阶段”之前做一些事情。它会做什么完全取决于你。如果需要,您至少需要根据某些逻辑执行下一步(操作)或阻止操作。

最后,像您发布的那个自定义中间件正在根据 AJAX 调用的响应修改您传递的操作,使其更像是一个“拦截器”而不是一个简单的中间件。这么写,不是派发新的动作,更多的是与修改你传递的动作有关。

如果您想根据 ajax 调用的结果调度一个新操作,但不创建中间件/拦截器,您可以这样做:

const postSomethingAction = postObject => 
    return async dispatch => 
        dispatch(postSomethingPending())
        const response = await Api.postSomething(postObject)
        if (response.message) 
            dispatch(postSomethingError(response))
        
        else 
            dispatch(postSomethingSuccess(response.data))
        
    

在这个例子中,我们使用 Thunk 创建一个动作,根据 Api.postSomething 的结果调度另一个动作

【讨论】:

@iba.Great.感谢您发布更多见解 在您的示例中,我想调用 postSomethingAction,然后我需要正确调用它。;就像 dspatch(postSomethingAction (myobject)) 是的,您将发送 postSomething,它最初会产生一个 POST_SOMETHING_PENDING 操作,然后根据 ajax 调用的结果,它会发送一个 POST_SOMETHING_SUCCESS 或 POST_SOMETHING_FAIL,从而更清楚地跟踪状态变化并使您能够做某事,直到服务器响应您的请求。它也比在中间件中做的“魔法”少一点,但它更冗长,因为你需要为所有基于你的 ajax 行为不同的动作编写类似的东西(只有当他们这样做时)

以上是关于Redux Thunk vs Redux 自定义中间件的主要内容,如果未能解决你的问题,请参考以下文章

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

Redux Thunk + Axios “操作必须是普通对象。使用自定义中间件进行异步操作。”

Redux thunk - 错误 · 动作必须是普通对象。使用自定义中间件进行异步操作,即使调度具有键类型的对象

自定义 Redux 中间件 - 调度到中间件链的开头?

ReactJS + Redux + Reduc-thunk 无法调度承诺

Reducer 返回未定义(Redux-Thunk 和 Promise)