如何让多个Reducer根据一组常见的操作触发更新而不重复自己?

时间:2016-10-27 06:01:06

标签: redux

我希望我的应用程序中有许多不同的redux操作可以触发特定reducer中的常用功能。我想避免在reducer寻找的每个动作创建者(如doThing:true)中重复一些标记。我也不希望让reducer只查找属于这个类别的每个单独的动作,因为这也需要有人记住每次添加新动作时都这样做,比如添加标志。

我想在每次调度其中一个动作时调度第二个动作。这不难做到,但每次发生一件事时我宁愿不发送2个动作。这似乎会污染州的历史。

有没有解决这个问题的常用方法?

有关我的具体问题的更多上下文,该特定功能与我的应用用于与我们的API通信的API客户端相关。在每次成功的响应中,我们都希望在reducer中做一些事情来更新状态,并且在每次失败的响应中,我们都想做其他事情。

有许多不同的成功和失败操作(例如ITEM_FETCH_SUCCESS或WIDGET_UPDATE_FAILURE),并且在添加新的操作时很难记住要为所有操作添加标记。

由于所有api请求都通过单个函数,因此该函数可以调度通用的REQUEST_SUCCESS和REQUEST_FAILURE操作。但这意味着服务器的每个响应都会调度2个动作(REQUEST_SUCCESS和ITEM_FETCH_SUCCESS)。这显然不理想,因为这意味着我的州历史上会有更多的行动。

2 个答案:

答案 0 :(得分:2)

假设通用REQUEST_SUCCESSREQUEST_FAILURE动作正在更新状态树的特定部分,那么可以将它们作为不同的动作分派。这样做并不一定意味着污染您的州历史,而只是对应用程序意图的更好的描述

  • ITEM_FETCH_SUCCESS:更改item

  • 的状态
  • REQUEST_SUCCESS:更改request

  • 的状态
  • WIDGET_UPDATE_FAILURE:更改widget

  • 的状态
  • REQUEST_FAILURE:更改request

  • 的状态

你可以看到,虽然这些行为密切相关,但它们并不一定与改变州树的不同部分相同。

接受这一点,问题是:如何最好地实施动作对,以便添加新动作并不意味着记住添加其相应的REQUEST_*合作伙伴?

我会考虑应用一个简单的redux中间件组件。这可以拦截您的api的返回并自动发送相应的REQUEST_*操作。

以下是一些实时代码的示例。此中间件拦截由websocket引发的disconnect事件,并自动调度自定义操作。它至少表明了原则:

//Dispatch a disconnect action when the websocket disconnects
//This is the custom action provided by the middleware

import io from 'socket.io-client'
import { actions } from './action'

const websocket = ({ websocketUrl }) => store => {
  const socket = io(websocketUrl)
  socket.on('disconnect', () => store.dispatch(actions.disconnect()))
}

export default websocket
//Apply the custom middleware via the redux createStore function
//Also include the thunk middleware because it is useful

import { applyMiddleware } from 'redux'
import thunk from 'redux-thunk'
import websocket from './middleware'

function websocketize (opts) {
  return createStore => (reducers, initial, enhancer) => {
    const middleware = applyMiddleware(thunk, websocket(opts))
    return createStore(reducers, initial, middleware)
  }
}

export default websocketize
// Create the top-level redux store passing in the custom middleware enhancer

const opts = {websocketUrl: env.WEBSOCKET_URL}
const store = createStore(reducers, websocketize(opts))

答案 1 :(得分:0)

此实现将所有内容保留在reducers中,而不是在拦截中使用逻辑(中间件)。两种方式都有效。

尝试 sub-reducer 模式。我看到它使用时通常感觉很粗糙(因为它通常使用错误),但你的情况听起来很完美。

  1. 将您的Reducer中的重复功能提取为一个 子减速机。
  2. 然后将减速器作为函数传递给所有需要它的人。
  3. 然后将动作和状态传递给减速器。
  4. 子减速器执行它的操作并将该状态返回到 你的父减速器让你用它做任何你想做的事 那里(即返回它,改变一些,一些逻辑)。
  5. Also if you are tired of worrying about typing out "all the stuff" for async then I highly recommend you try out redux-crud.js

    这也是可能的,一个简单的方法就是将每个动作都给一个减速器,让它在一个案例中做一个常见的变异:

    case actionOne
         actionTwo 
         actionThree
         actionFour: { 
           //do common stuff here
         }
    

    。但是你说它没有重复,它是相似的,这意味着你的情况因分支逻辑而变得复杂。我也不推荐这个。保持案例简单,以便您可以轻松捕获无效的突变。 这应该是redux的超级强大功能,很容易发现变异错误。由于这个原因以及其他许多原因,我不建议在前端对数据进行规范化。