Skip to content

Instantly share code, notes, and snippets.

@amnox
Created March 25, 2019 10:18
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save amnox/5471f7e4c79546af3d50218db21e816a to your computer and use it in GitHub Desktop.
Save amnox/5471f7e4c79546af3d50218db21e816a to your computer and use it in GitHub Desktop.
A demo implementation of Reducer Injection is React
import React from 'react';
import PropTypes from 'prop-types';
import hoistNonReactStatics from 'hoist-non-react-statics';
import invariant from 'invariant';
import isEmpty from 'lodash/isEmpty';
import isFunction from 'lodash/isFunction';
import isString from 'lodash/isString';
import checkStore from './checkStore';
import createReducer from '../reducers';
import conformsTo from 'lodash/conformsTo';
import isFunction from 'lodash/isFunction';
import isObject from 'lodash/isObject';
import createReducer from './reducers';
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',
);
}
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));
};
}
function getInjectors(store) {
checkStore(store);
return {
injectReducer: injectReducerFactory(store, true),
};
}
export default ({ key, reducer }) => WrappedComponent => {
class ReducerInjector extends React.Component {
static WrappedComponent = WrappedComponent;
static contextTypes = {
store: PropTypes.object.isRequired,
};
static displayName = `withReducer(${WrappedComponent.displayName ||
WrappedComponent.name ||
'Component'})`;
componentWillMount() {
const { injectReducer } = this.injectors;
injectReducer(key, reducer);
}
injectors = getInjectors(this.context.store);
render() {
return <WrappedComponent {...this.props} />;
}
}
return hoistNonReactStatics(ReducerInjector, WrappedComponent);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment