Reactjs 使用react路由器4动态加载redux还原器
我正在基于组件拆分代码,我只想在组件加载时注入我的还原程序,而不是从一开始就在存储中将它们全部堆叠起来 在react路由器3中,它非常简单,但我似乎无法让它与react路由器4一起工作 这是减速器和商店: reducers.jsReactjs 使用react路由器4动态加载redux还原器,reactjs,redux,react-router,Reactjs,Redux,React Router,我正在基于组件拆分代码,我只想在组件加载时注入我的还原程序,而不是从一开始就在存储中将它们全部堆叠起来 在react路由器3中,它非常简单,但我似乎无法让它与react路由器4一起工作 这是减速器和商店: reducers.js import { combineReducers } from 'redux' import { routerReducer } from 'react-router-redux' import modalReducer from '../modules/modal'
import { combineReducers } from 'redux'
import { routerReducer } from 'react-router-redux'
import modalReducer from '../modules/modal'
export default combineReducers({
routing : routerReducer,
modal : modalReducer
})
store.js
import { createStore, applyMiddleware, compose } from 'redux'
import { routerMiddleware } from 'react-router-redux'
import thunk from 'redux-thunk'
import createHistory from 'history/createBrowserHistory'
import rootReducer from './reducers'
export const history = createHistory()
const initialState = {}
const enhancers = []
const middleware = [
thunk,
routerMiddleware(history)
]
if (process.env.NODE_ENV === 'development') {
const devToolsExtension = window.devToolsExtension
if (typeof devToolsExtension === 'function') {
enhancers.push(devToolsExtension())
}
}
const composedEnhancers = compose(
applyMiddleware(...middleware),
...enhancers
)
const store = createStore(
rootReducer(),
initialState,
composedEnhancers
)
export default store
我正在为路由使用延迟加载
如何实现拆分减速器
我想注入异步还原程序,如下所示:
function createReducer(asyncReducers) {
return combineReducers({
...asyncReducers,
system,
router,
})
}
function injectReducer(store, { key, reducer }) {
if (Reflect.has(store.asyncReducers, key)) return
store.asyncReducers[key] = reducer
store.replaceReducer(createReducer(store.asyncReducers))
}
在react router v4中,对于异径管的异步注入,请执行以下操作:
在reducer.js文件中添加一个名为createReducer的函数,该函数将injectedReducer作为arg接收并返回组合的reducer:
/**
* Creates the main reducer with the dynamically injected ones
*/
export default function createReducer(injectedReducers) {
return combineReducers({
route: routeReducer,
modal: modalReducer,
...injectedReducers,
});
}
然后,在您的store.js文件中
import createReducer from './reducers.js';
const store = createStore(
createReducer(),
initialState,
composedEnhancers
);
store.injectedReducers = {}; // Reducer registry
现在,为了在react容器装载时以异步方式注入reducer,您需要在容器中使用该函数,然后将所有reducer与connect组合在一起。
示例组件Todo.js:
// example component
import { connect } from 'react-redux';
import { compose } from 'redux';
import injectReducer from 'filepath/injectReducer';
import { addToDo, starToDo } from 'containers/Todo/reducer';
class Todo extends React.Component {
// your component code here
}
const withConnect = connect(mapStateToProps, mapDispatchToProps);
const addToDoReducer = injectReducer({
key: 'todoList',
reducer: addToDo,
});
const starToDoReducer = injectReducer({
key: 'starredToDoList',
reducer: starToDo,
});
export default compose(
addToDoReducer,
starToDoReducer,
withConnect,
)(Todo);
是了解整个设置的极好来源。您可以在几秒钟内生成一个示例应用程序。
injectReducer.js、configureStore.js(在您的例子中是store.js)的代码,实际上整个配置都可以从react样板文件中获取。具体链接可在此处找到 为了异步注入还原程序,在第一步中,您需要以您提到的格式编写create store: 减速器
import invariant from 'invariant';
import isEmpty from 'lodash/isEmpty';
import isFunction from 'lodash/isFunction';
import isObject from 'lodash/isObject';
import isString from 'lodash/isString';
import createReducer from '../reducers'; //The createStoreFile
/**
* Validate the shape of redux store
*/
function checkStore(store) {
const shape = {
dispatch: isFunction,
subscribe: isFunction,
getState: isFunction,
replaceReducer: isFunction,
runSaga: isFunction,
injectedReducers: isObject,
injectedSagas: isObject,
};
invariant(
conformsTo(store, shape),
'(app/utils...) injectors: Expected a valid redux store'
);
}
export function injectReducerFactory(store, isValid) {
return function injectReducer(key, reducer) {
if (!isValid) checkStore(store);
invariant(
isString(key) && !isEmpty(key) && isFunction(reducer),
'(app/utils...) injectReducer: Expected `reducer` to be a reducer function'
);
// Check `store.injectedReducers[key] === reducer` for hot reloading when a key is the same but a reducer is different
if (Reflect.has(store.injectedReducers, key) && store.injectedReducers[key] === reducer) return;
store.injectedReducers[key] = reducer; // eslint-disable-line no-param-reassign
store.replaceReducer(createReducer(store.injectedReducers));
};
}
export default function getInjectors(store) {
checkStore(store);
return {
injectReducer: injectReducerFactory(store, true),
};
}
在Reducer中,唯一的区别是获取AsyncReducer作为createReducer函数的输入,并按以下方式将其用于组合Reducer
function createReducer(asyncReducers) {
return combineReducers({
...asyncReducers,
system,
router,
})
}
import { createStore, applyMiddleware, compose } from 'redux'
import { routerMiddleware } from 'react-router-redux'
import thunk from 'redux-thunk'
import createHistory from 'history/createBrowserHistory'
import rootReducer from './reducers'
export const history = createHistory()
const initialState = {}
const middleware = [
thunk,
routerMiddleware(history)
]
const enhancers = [
applyMiddleware(...middlewares),
];
/* eslint-disable no-underscore-dangle */
const composeEnhancers =
process.env.NODE_ENV !== 'production' &&
typeof window === 'object' &&
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({
// TODO Try to remove when `react-router-redux` is out of beta, LOCATION_CHANGE should not be fired more than once after hot reloading
// Prevent recomputing reducers for `replaceReducer`
shouldHotReload: false,
})
: compose;
/* eslint-enable */
const store = createStore(
rootReducer(),
initialState,
composeEnhancers(...enhancers)
);
// Extensions
store.injectedReducers = {}; // Reducer registry
/ Make reducers hot reloadable, see http://mxs.is/googmo
/* istanbul ignore next */
if (module.hot) {
module.hot.accept('./reducers', () => {
store.replaceReducer(createReducer(store.injectedReducers));
});
}
export default store;
配置存储
您的configureStore文件应如下所示。我对你的结构做了一些改变。首先,我在增强器中应用了中间件,以便能够使用chromeredux DevTool扩展(如果安装了chromeredux DevTool扩展,则使用redux compose)(还可以为异步减速机使用减速机热重载)
组件
一个简单的组件如下所示。正如您在该组件中所看到的,我们首先将连接到组件以响应redux,并可以使用mapStateToProps
和mapDispatchToProps
,然后为了为该文件注入缩减器,我们需要两件事:
1) reducer文件,2)注入reducer函数
之后,我们将组合connect和reducerInjected到组件
import React from 'react';
import { connect } from 'react-redux';
import { compose } from 'redux';
import reducerForThisComponent from './reducer';
import injectReducer from 'path_to_recuer_injector';
const Component = (props)=><div>Component</div>
function mapStateToProps (state){
return {}
}
const withConnect = connect(mapStateToProps);
const withReducer = injectReducer({ key: 'login', reducerForThisComponent });
export default compose(
withReducer,
withConnect,
)(Component);
getInjectors.js
import invariant from 'invariant';
import isEmpty from 'lodash/isEmpty';
import isFunction from 'lodash/isFunction';
import isObject from 'lodash/isObject';
import isString from 'lodash/isString';
import createReducer from '../reducers'; //The createStoreFile
/**
* Validate the shape of redux store
*/
function checkStore(store) {
const shape = {
dispatch: isFunction,
subscribe: isFunction,
getState: isFunction,
replaceReducer: isFunction,
runSaga: isFunction,
injectedReducers: isObject,
injectedSagas: isObject,
};
invariant(
conformsTo(store, shape),
'(app/utils...) injectors: Expected a valid redux store'
);
}
export function injectReducerFactory(store, isValid) {
return function injectReducer(key, reducer) {
if (!isValid) checkStore(store);
invariant(
isString(key) && !isEmpty(key) && isFunction(reducer),
'(app/utils...) injectReducer: Expected `reducer` to be a reducer function'
);
// Check `store.injectedReducers[key] === reducer` for hot reloading when a key is the same but a reducer is different
if (Reflect.has(store.injectedReducers, key) && store.injectedReducers[key] === reducer) return;
store.injectedReducers[key] = reducer; // eslint-disable-line no-param-reassign
store.replaceReducer(createReducer(store.injectedReducers));
};
}
export default function getInjectors(store) {
checkStore(store);
return {
injectReducer: injectReducerFactory(store, true),
};
}
现在一切都已设置好,您已经拥有了所有功能,例如减速机注入,甚至在开发阶段支持热模块减速机负载。然而,我强烈建议两件事:
查看react样板文件
可能是一个不错的主意,因为它提供了许多优秀的功能,这些功能是通过针对大规模应用程序的最佳实践实现的
如果您计划进行代码拆分,这意味着您将有一个具有可伸缩性问题的应用程序。因此,我建议不要使用redux thunk,而是使用redux saga。最好的解决方案是异步注入saga中间件
,并在卸载组件后立即弹出saga文件。这种做法可以从几个方面改进您的应用程序
您不仅可以注入还原程序,还可以注入传奇,按块加载页面,并使用自己的css和资产(图像、图标)使您的组件真正称职,而无需全局,所有内容都动态地附加到应用程序。关于它有一个完整的哲学-,这里有一个样板,追求一个类似的想法:
我意识到我的答案不够完整,但它可能会为接下来的步骤提供更多的想法。这种复杂设置的原因是什么?你的应用真的需要多态还原器吗?让所有这些产品都在同一家商店中提供,并为每个组件使用正确的产品,怎么样?这在很大程度上可能会很快失控projects@S.Schenk你能把减速机分开吗?你还有什么问题吗?如果没有,请接受其中一个答案,以便帮助其他人在将来看到问题:)