0

目标

当路线发生变化时,我想更改减速器(并为它们提供新状态)。

当前尝试

/components/:slug我有一个由我的ComponentPage减速器处理的 slug ( ) 设置的路线。这个 reducer 注意到路由发生了变化(通过 Redux-saga),并有机会获取与当前:slug.

当路由器第一次更新到一个/components页面时,状态看起来像这样:

route: {...}
language: {...}
theme: {...}
componentPage: {
  content: {[default / empty]}
}

ComponentPage获取与 相关的数据后:slug,它看起来像这样:

route: {...}
language: {...}
theme: {...}
componentPage: {
  content: {...}
  liveExample: {...}
  tabCollection: {...}
}

在上面的状态树中,像liveExampletabCollection表示由它们自己的 reducer 管理的新域(并且它们的初始状态由 设置componentPageReducer)。

我的意图是像这样的项目将ComponentPage根据页面动态设置,:slug以便可以将它们换成其他组件,而不会用可能出现在组件页面的每个可能实例上的每个可能组件乱扔状态树。

问题

我目前设置了配置文件来导入每个页面需要的特定减速器,以便它们可以ComponentPage基于:slug. 不幸的是,我当前的实现方法仅足以处理初始渲染——在传递之后,导入的 reducer 被它们返回的对象替换。

我目前正在处理的对象的示例ComponentPage

pageConfiguration = {
  content: {...},
  liveExample: (state, action) => liveExampleReducer(state || liveExampleConfiguration, action),
  tabCollection: (state, action) => tabCollectionReducer(state || tabCollectionConfiguration, action),
}

关于我如何做到这一点的说明

ReduxcombineReducers会返回一些这样的结构:

liveExample: liveExampleReducer(liveExampleConfiguration, action),
tabCollection: tabCollectionReducer(tabCollectionConfiguration, action),

那将是理想的(如果我只知道如何将这些列为适当的减速器)。相反,我必须使函数可调用,以便我可以传入action(当componentPageReducer不匹配时action.type,它仍然会尝试手动调用这些动态加载的减速器,如下所示)。(他们也接受state || configuration这样当这些被随后调用时,他们不会继续使用配置/初始数据重新初始化)。

ComponentPage/reducer.js

export default function componentPageReducer(state = initialState, action) {
  switch (action.type) {
    case FETCH_SLUG:
      // gets the `pageConfiguration` object from above,
      // and generates the state by manually mapping through
      // its functions and calling them
      if (pages.has(action.payload.slug)) {
        return pages.get(action.payload.slug).map((x) => {
          if (typeof x === 'function') {
            return x(undefined, action)
          }
          return x
        })
      }
      return state
    default:
      // an attempt at calling the now-nonexistent
      // imported reducer functions
      return state.map((x) => {
        if (typeof x === 'function') {
          return x(state, action)
        }
        return x
      })
  }
}

可能的解决方案

所以,据我所知,如果我将 reducer 函数本身存储在 state 中并将它们的值映射到不同的键上,这样它们就不会替换自己,那么这可能会起作用,但是......看起来我正在下降奇怪的路在这里return

我认为我目前正在拼凑一些可能不应该被认为是适当的 Reducer Composition 的东西。我不知道是否有更优雅的方式来处理这种情况。

4

1 回答 1

1

动态 reducer 切片的标准方法是保留所有现有切片 reducer 的对象,当您需要在运行时添加一个新对象时,更新该对象并重新运行`combineReducers. 给你一个基本的想法:

let sliceReducers = {
    first : firstReducer,
    second : secondReducer
};

const initialRootReducer = combineReducers(sliceReducers);
const store = createStore(initialRootReducer);


// sometime later

sliceReducers = {
    ...sliceReducers,
    third : thirdReducer
}

const newRootReducer = combineReducers(sliceReducers);
store.replaceReducer(newRootReducer);

我的React/Redux 链接列表的Redux Techniques#Reducers部分有几篇关于该主题的文章。您可能还想查看React-Boilerplate 工具包中的实用程序。injectAsyncReducer

于 2017-03-17T21:30:21.493 回答