redux-hook
v0.1.3
Published
Redux middleware to subscribe to specifically events and state tree changes
Downloads
8
Maintainers
Readme
redux-hook
This is a Redux middleware that allows you to subscribe to specific changes in your Redux application, and all your subscribers are passed in the action object, the new state, then the last state. The module exports a function that returns an object with middleware
and decorator
properties. You apply the middleware
property like a normal Redux middleware, and you pass your store instance to decorator
to add the functions described below.
Example
import {
createStore,
applyMiddleware
} from 'redux';
import createHookMiddleware from 'redux-hook';
const {
middleware: reduxHook,
decorator
} = createHookMiddleware();
const store = decorator(createStore((state, action) => {
// some reducer
}, applyMiddleware(reduxHook)));
const {
subscribeToState,
subscribeToStateOnce,
subscribeToKey,
subscribeToKeyOnce,
subscribeToEvent,
subscribeToEventOnce
} = store;
// set up subscribers
export default store;
Function descriptions
subscribeToState
This is the core subscribe function that subscribes to any change in the state tree. The difference is that this function is passed the action object, the current state, and the last state tree, so that you don't have to keep track of references manually.
const unsubscribe = store.subscribeToState((action, currentTree, lastTree) => {
if (lastTree.someBranch !== currentTree.someBranch) {
store.dispatch({ type: 'SOME_EVENT' });
}
});
subscribeToStateOnce
This function subscribes to state changes and automatically unsubscribes after it has been called once.
subscribeToKey
This function takes two arguments, the first argument can be a string representing one key in the state tree on which to listen for changes. If the first argument is a string, the second argument will be a function that will be called whenever that branch of the state tree changes, called with the last branch of the state tree by that key and the current one as arguments. If, however, the first argument to the function is an array, the second argument must be a function that will be called with the last entire state tree then the current state tree passed in as arguments.
const unsubscribe = store.subscribeToKey('someBranch', (action, currentState, lastState) => {
// do something with changed properties
});
const otherUnsubscribe = store.subscribeToKey(['someBranch', 'someOtherBranch'], (action, currentTree, lastTree) => {
// do something when either someBranch or someOtherBranch has changed
});
subscribeToKeyOnce
This function has the same behavior as Store#subscribeToKey
but will be unsubscribed automatically after the function is called once.
subscribeToEvent
This function takes an event name as its first argument and the second argument will be a function that will be called with the action object, the current state tree, and the last state tree whenever that event is dispatched.
const unsubscribe = store.subscribeToEvent('SOME_EVENT', (action, currentTree, lastTree) => {
// do something with state or action payload when SOME_EVENT is dispatched
});
subscribeToEventOnce
This function has the same behavior as subscribeToEvent
except it is unsubscribed after the function is called once.
Motivation & Design Patterns
Manually keeping track of references to the last and current state tree in each of your subscribers can result in ugly code and can be a source of infinite recursion bugs, notably when calling dispatch
from within subscribers. These subscribers handle this mechanism for you.
subscribeToEvent
can be a clean way to launch actions with side-effects from a container component, while keeping your container a pure function of the redux state and dispatch function, and it also allows separation of your core application and network logic from your container. You might see a similar pattern in applications that make use of react-saga.
Example of a pure container that executes networked logic via an event subscriber:
// in SomeContainer.js
import SomeComponent from './SomeComponent';
import { connect } from 'react-redux';
export default connect(({ someBranch }) => ({ someBranch }), (dispatch) => ({
onClick() {
dispatch({
type: 'REQUEST_FETCH_DATA'
});
}
}));
// somewhere in store.js
subscribeToEvent('REQUEST_FETCH_DATA', () => {
fetchDataAsync((err, result) => {
dispatch({
type: 'DATA_FETCH_COMPLETE',
payload: result
});
});
});
Author
Raymond Pulver IV
License
MIT