我要迁移到Redux。
我的应用程序包含很多部分(页面,组件),所以我想创建许多reducer。 Redux示例显示我应该使用combineReducers()
生成一个reducer。
另外据我所知,Redux应用程序应该有一个存储,并且一旦应用程序启动就会创建它。在创建商店时,我应该通过我的组合减速机。如果应用程序不是太大,这是有道理的。
但是,如果我构建多个JavaScript包怎么办?例如,每个应用程序页面都有自己的包。我认为在这种情况下,一个联合减速器并不好。我查看了Redux的来源,并找到了replaceReducer()
函数。这似乎是我想要的。
我可以为我的应用程序的每个部分创建组合的reducer,并在我在应用程序的各个部分之间移动时使用replaceReducer()
。
这是一个好方法吗?
答案 0 :(得分:222)
更新:另请参阅how Twitter does it。
这不是一个完整的答案,但应该可以帮助你开始。请注意,我不丢弃旧的Reducer - 我只是在组合列表中添加新的。我认为没有理由抛弃旧的Reducer - 即使在最大的应用程序中你也不可能拥有数千个动态模块,这就是可能想要断开应用程序中某些Reducer的地步。
import { combineReducers } from 'redux';
import users from './reducers/users';
import posts from './reducers/posts';
export default function createReducer(asyncReducers) {
return combineReducers({
users,
posts,
...asyncReducers
});
}
import { createStore } from 'redux';
import createReducer from './reducers';
export default function configureStore(initialState) {
const store = createStore(createReducer(), initialState);
store.asyncReducers = {};
return store;
}
export function injectAsyncReducer(store, name, asyncReducer) {
store.asyncReducers[name] = asyncReducer;
store.replaceReducer(createReducer(store.asyncReducers));
}
import { injectAsyncReducer } from './store';
// Assuming React Router here but the principle is the same
// regardless of the library: make sure store is available
// when you want to require.ensure() your reducer so you can call
// injectAsyncReducer(store, name, reducer).
function createRoutes(store) {
// ...
const CommentsRoute = {
// ...
getComponents(location, callback) {
require.ensure([
'./pages/Comments',
'./reducers/comments'
], function (require) {
const Comments = require('./pages/Comments').default;
const commentsReducer = require('./reducers/comments').default;
injectAsyncReducer(store, 'comments', commentsReducer);
callback(null, Comments);
})
}
};
// ...
}
可能有更简洁的表达方式 - 我只是在表达这个想法。
答案 1 :(得分:23)
这就是我在当前应用程序中实现它的方法(基于Dan在GitHub问题上的代码!)
// Based on https://github.com/rackt/redux/issues/37#issue-85098222
class ReducerRegistry {
constructor(initialReducers = {}) {
this._reducers = {...initialReducers}
this._emitChange = null
}
register(newReducers) {
this._reducers = {...this._reducers, ...newReducers}
if (this._emitChange != null) {
this._emitChange(this.getReducers())
}
}
getReducers() {
return {...this._reducers}
}
setChangeListener(listener) {
if (this._emitChange != null) {
throw new Error('Can only set the listener for a ReducerRegistry once.')
}
this._emitChange = listener
}
}
在引导您的应用程序时创建一个注册表实例,传入将包含在条目包中的reducer:
// coreReducers is a {name: function} Object
var coreReducers = require('./reducers/core')
var reducerRegistry = new ReducerRegistry(coreReducers)
然后在配置商店和路由时,使用可以将reducer注册表赋予的函数:
var routes = createRoutes(reducerRegistry)
var store = createStore(reducerRegistry)
这些功能类似于:
function createRoutes(reducerRegistry) {
return <Route path="/" component={App}>
<Route path="core" component={Core}/>
<Route path="async" getComponent={(location, cb) => {
require.ensure([], require => {
reducerRegistry.register({async: require('./reducers/async')})
cb(null, require('./screens/Async'))
})
}}/>
</Route>
}
function createStore(reducerRegistry) {
var rootReducer = createReducer(reducerRegistry.getReducers())
var store = createStore(rootReducer)
reducerRegistry.setChangeListener((reducers) => {
store.replaceReducer(createReducer(reducers))
})
return store
}
以下是使用此设置创建的基本实例,其来源为:
它还涵盖了为所有减速器启用热重新加载的必要配置。
答案 2 :(得分:6)
现在有一个模块可以将注入Reducer添加到redux存储中。它被称为Redux Injector。 https://github.com/randallknutson/redux-injector
以下是如何使用它:
不要组合减速器。而是将它们放在函数的(嵌套)对象中,而不是将它们组合在一起。
使用redux-injector中的createInjectStore而不是redux中的createStore。
使用injectReducer注入新的reducer。
以下是一个例子:
import { createInjectStore, injectReducer } from 'redux-injector';
const reducersObject = {
router: routerReducerFunction,
data: {
user: userReducerFunction,
auth: {
loggedIn: loggedInReducerFunction,
loggedOut: loggedOutReducerFunction
},
info: infoReducerFunction
}
};
const initialState = {};
let store = createInjectStore(
reducersObject,
initialState
);
// Now you can inject reducers anywhere in the tree.
injectReducer('data.form', formReducerFunction);
完全披露:我是模块的创建者。
答案 3 :(得分:4)
截至2017年10月:
实现Dan建议的内容,仅此而已,无需触及您的商店,项目或习惯
还有其他库,但它们可能包含太多依赖项,示例少,使用复杂,与某些中间件不兼容或要求您重写状态管理。从Reedux的介绍页面复制:
答案 4 :(得分:1)
我们发布了一个新库,该库有助于调制Redux应用程序,并允许动态添加/删除Reducers和中间件。
请看一看 https://github.com/Microsoft/redux-dynamic-modules
模块具有以下优点:
模块可以轻松地在整个应用程序中或在多个相似的应用程序之间重复使用。
组件声明了它们所需的模块,redux-dynamic-modules确保为该组件加载了模块。
功能
示例方案
答案 5 :(得分:0)