【问题标题】:Redux: using thunk middleware and combineReducers introduces extra key to getStateRedux:使用 thunk 中间件和 combineReducers 为 getState 引入了额外的密钥
【发布时间】:2016-04-12 12:24:19
【问题描述】:

问题:在引入Redux.combineReducers 之前使用thunk 中间件时,传递给thunk 的getState 正确返回具有正确键的对象。重构为使用Redux.combineReducers 后,传递给thunk 的getState 现在返回一个带有嵌套键的对象。请参阅下面的代码(希望)说明我的观点。这可能导致潜在的维护噩梦,即必须不断为任何访问状态的thunk 方法获取正确的密钥。

问题:有没有一种简单的方法可以在thunk 中设置正确的上下文键?当我结合减速器并且必须插入键来访问正确的状态时,代码感觉很脆弱。我错过了一些简单的东西吗?

代码前:

const Redux = require('redux'),
    Thunk = require('redux-thunk');

// this is an action generator that returns a function and is handled by thunk
const doSomethingWithFoo = function() {
    return function(dispatch, getState) {
        // here we're trying to get state.fooValue
        const fooValue = getState().fooValue;
        dispatch({ type: "DO_SOMETHING", fooValue });
    }
};
// this is a simple action generator that returns a plain action object
const doSimpleAction = function(value) {
    // we simply pass the value to the action. 
    // we don't have to worry about the state's context at all.
    // combineReducers() handles setting the context for us.
    return { type: "SIMPLE_ACTION", value };
}

const fooReducer(state, action) {
    // this code doesn't really matter
    ...
}

const applyMiddleware = Redux.applyMiddleware(Thunk)(Redux.createStore);
const fooStore = applyMiddleware(fooReducer);

代码之后(引入更全球化的应用商店):

// need to rewrite my thunk now because getState returns different state shape
const doSomethingWithFoo = function() {
    return function(dispatch, getState) {
        // here we're trying to get state.fooValue, but the shape is different
        const fooValue = getState().foo.fooValue;
        dispatch({ type: "DO_SOMETHING", fooValue });
    }
};


const appReducers = Redux.combineReducers({
    foo: fooReducer,
    bar: barReducer,
});
const appStore = applyMiddleware(appReducers);

【问题讨论】:

  • 我不认为这与 thunk 中间件有任何关系。它只是拥有多个减速器然后使用combinerReducers 的副产品。 doSomethingWithFoo 到底是什么?它是一个动作还是组件的一部分?
  • 您可以看到in the combineReducers function 它期望将先前的状态附加到提供的键上。
  • 是的,thunk 中间件不会对密钥进行任何修改。传递给我的操作返回的函数的getState 只会天真地返回任何状态。在after 版本中,它现在具有嵌套键。该问题特定于使用thunk 中间件。我的问题是,在thunk 中维护getState 上下文将成为一场噩梦,因为您必须不断更新密钥。我将尝试编辑帖子以使其更清晰。
  • 我了解您的问题。但是,我也想知道在 thunk 上使用 getState 是否会因此被视为反模式(还要记住,动作调度程序上的读取状态有点可疑)。
  • @E_net4:是的,你是对的。我认为答案是重构。

标签: javascript redux redux-thunk


【解决方案1】:

你想太多了。根据定义,store.getState() 返回整个状态,combineReducers() 将多个 sub-reducer 拉到一个更大的对象中。两者都按预期工作。您正在编写自己的应用程序,因此您要负责实际组织状态形状和处理它的方式。如果你觉得这种方式太“脆弱”了,你可以自己去寻找一种结构的好方法,但这对 Redux 来说不是问题。

此外,在动作创建器中使用getState() 来确定要做什么是一种完全有效的方法。事实上,Redux 文档的 Reducing Boilerplate 部分甚至将其作为演示:

export function addTodo(text) {
  // This form is allowed by Redux Thunk middleware
  // described below in “Async Action Creators” section.
  return function (dispatch, getState) {
    if (getState().todos.length === 3) {
      // Exit early
      return
    }

    dispatch(addTodoWithoutCheck(text))
  }
}

【讨论】:

  • 是的,你是对的。我认为答案是重构,所以我不依赖 getState。尽管它来自 Redux 文档,但我并不完全同意您在回复中引用的示例。假设在某个时候,我想将 .todos 减速器嵌套在另一个存储键下。然后,我必须返回并修改我所有关闭.todos 的动作生成器。如果将引用的示例重构为 addTodo(todos, text),则可以从 thunk 中删除 w/ getState()。我可能是错的,但我觉得这样更容易维护。
  • 作为上述内容的补充,reducers 可以进行改造,以便在缩减时间内执行检查(即todos.length === 0),从而避免读取动作创建者。
  • 除非 thunk 代表程序的高级逻辑,否则我仍然会避免在 thunk 中使用 getState()
  • @E_net4:但是,如果它是类似于网络请求的东西,如果已经缓存了三个待办事项,则可以避免,那么就不能外包给reducer。 thunk 必须以某种方式读取状态。在这种情况下,我看不出有任何方法可以避免它。
  • @FighterJet 事实上,我不久前也得出结论,在某些情况下我们无法避免这种模式。让我想知道流行的 Redux sagas 是否会为该用例提供更清洁的解决方案。
【解决方案2】:

再想一想,我认为答案是重构doSomethingWithFoo动作生成器,使其接受fooValue作为参数。那我就不用担心状态对象形状的变化了。

const doSomethingWithFoo(fooValue) {
    return function(dispatch, getState) {
        // now we don't have to worry about the shape of getState()'s result
        dispatch({ type: "DO_SOMETHING", fooValue });
    }
}

【讨论】:

    猜你喜欢
    • 2018-06-03
    • 2020-02-03
    • 2018-01-16
    • 2021-10-04
    • 2022-08-19
    • 2018-01-31
    • 2020-11-29
    • 2017-08-31
    • 1970-01-01
    相关资源
    最近更新 更多