Skip to content

Instantly share code, notes, and snippets.

@butchler
Last active August 15, 2016 21:28
Show Gist options
  • Save butchler/28988d505af4de49ce83e6cc28bc7c36 to your computer and use it in GitHub Desktop.
Save butchler/28988d505af4de49ce83e6cc28bc7c36 to your computer and use it in GitHub Desktop.
// Wrap combineReducers to pass a namespace as the third argument
// to each reducer, so that each reducer can know where it is in
// the state and accept namespaced actions targeted for it.
function combineReducersWithNamespace(reducers) {
return (state, action, namespace) => {
const newState = {};
Object.keys(reducers).forEach(name => {
const reducerNamespace = namespace ?
namespace + '.' + name :
name;
newState[name] = reducer(state[name], action, namespace);
});
return newState;
};
}
// Higher-order reducer to create a namespacedReducer reducer,
// which accepts namespaced actions with a matching namespace.
function namespacedReducer(reducer) {
return (state, action, namespace) => {
if (namespace !== undefined &&
action.type === 'NAMESPACED_ACTION' &&
action.payload.namespace === namespace) {
return reducer(state, action.payload.action);
} else {
return reducer(state, action);
}
};
}
...
// Example
// =======
// State:
const store = createStore(combineReducersWithNamespace({
ui: combineReducersWithNamespace({
form1: namespacedReducer(formReducer),
form2: namespacedReducer(formReducer),
}),
});
...
// Higher-order reducer to create a namespacedReducer reducer,
// which accepts namespaced actions with a matching namespace.
function namespacedReducer(namespace, reducer) {
return (state, action) => {
if (action.type === 'NAMESPACED_ACTION' &&
action.payload.namespace === namespace) {
return reducer(state, action.payload.action);
} else {
return reducer(state, action);
}
};
}
// Wraps an action in another action so that it only gets
// handled by the namespacedReducer with the same namespace.
function namespacedAction(namespace, action) {
return {
type: 'NAMESPACED_ACTION',
payload: {
namespace,
action,
},
};
}
// Example
// =======
// State:
const store = createStore(combineReducers({
ui: combineReducers({
form1: namespacedReducer('ui.form1', formReducer),
form2: namespacedReducer('ui.form2', formReducer),
}),
});
// Connected component for form:
function mapStateToProps(state, ownProps) {
const formState = state.ui[ownProps.formId];
return {
state.errorMessage,
};
}
function mapDispatchToProps(dispatch, ownProps) {
const namespace = 'ui.' + formId;
return {
onSumbit: dispatch(namespacedAction(namespace, formOnSubmitAction));
};
}
const NamespacedForm = connect(mapStateToProps, mapDispatchToProps)(Form);
// Usage:
<NamespacedForm formId="form1" ... />
<NamespacedForm formId="form2" ... />
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment