Skip to content

Instantly share code, notes, and snippets.

@dthtien
Last active April 14, 2022 20:22
Show Gist options
  • Save dthtien/d9ba9faabc73ce62069793b622243b6f to your computer and use it in GitHub Desktop.
Save dthtien/d9ba9faabc73ce62069793b622243b6f to your computer and use it in GitHub Desktop.
React Redux code splitting
//uttils/createStore.js
import { combineReducers, applyMiddleware, createStore, compose } from "redux";
import reducerRegistry from "./reducerRegistry";
import createSagaMiddleware from "redux-saga";
export const sagaMiddleware = createSagaMiddleware();
const initialState = {};
const enhancers = [];
const middleware = [sagaMiddleware];
if (process.env.NODE_ENV === "development") {
// eslint-disable-next-line no-underscore-dangle
const devToolsExtension = window.__REDUX_DEVTOOLS_EXTENSION__;
if (typeof devToolsExtension === "function") {
enhancers.push(devToolsExtension());
}
}
const composedEnhancers = compose(
applyMiddleware(...middleware),
...enhancers
);
const reducer = combineReducers(reducerRegistry.reducers);
const store = createStore(reducer, initialState, composedEnhancers);
const combine = reducers => {
const reducerNames = Object.keys(reducers);
Object.keys(initialState).forEach(item => {
if (reducerNames.indexOf(item) === -1) {
reducers[item] = (state = null) => state;
}
});
return combineReducers(reducers);
};
reducerRegistry.emitChange = reducers =>
store.replaceReducer(combine(reducers));
export default store;
//index.js
import React from "react";
import ReactDOM from "react-dom";
import { createBrowserHistory } from "history";
import { Provider } from "react-redux";
import store from "./utils/createStore";
// core components
import SomeComponent from "layouts/SomeComponent.js";
const hist = createBrowserHistory();
ReactDOM.render(
<Provider store={store}>
<SomeComponent/>
</Provider>,
document.getElementById("root")
);
//utils/reducerInjector.js
import React from "react";
import { ReactReduxContext } from "react-redux";
import reducerRegistry from "./reducerRegistry";
import { sagaMiddleware } from "./createStore";
export default ({ key, reducer, saga }) => WrappedComponent => {
class ReducerInjector extends React.Component {
static WrappedComponent = WrappedComponent;
static contextType = ReactReduxContext;
static displayName = `withReducer(${WrappedComponent.displayName ||
WrappedComponent.name ||
"Component"})`;
constructor(props, context) {
super(props, context);
reducerRegistry.register(key, reducer);
if (saga) {
sagaMiddleware.run(saga);
}
}
render() {
return <WrappedComponent {...this.props} />;
}
}
return ReducerInjector;
};
//utils/reducerRegistry.js
export class ReducerRegistry {
constructor() {
this._emitChange = null;
this._reducers = {};
}
get reducers() {
return { ...this._reducers };
}
set emitChange(listener) {
this._emitChange = listener;
}
register(name, reducer) {
this._reducers = { ...this._reducers, [name]: reducer };
if (this._emitChange) {
this._emitChange(this.reducers);
}
}
}
const reducerRegistry = new ReducerRegistry();
export default reducerRegistry;
//views/SomeComponent/index.js
import React from "react";
import { connect } from "react-redux";
import { compose } from "redux";
import reducer, { reducerName as key } from "./reducer";
// import reducerRegistry from "utils/reducerRegistry";
import reducerInjector from "utils/reducerInjector";
function SomeComponent() {
const classes = useStyles();
return <h1>The awesome component!</h1>
}
const withConnect = connect(
null,
null
);
const withReducer = reducerInjector({ key, reducer });
export default compose(
withConnect,
withReducer
)(SomeComponent);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment