Created
March 25, 2019 10:18
-
-
Save amnox/5471f7e4c79546af3d50218db21e816a to your computer and use it in GitHub Desktop.
A demo implementation of Reducer Injection is React
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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