redux-advanced-subscribe

0.1.3 • Public • Published

redux-advanced-subscribe

This module exports a decorator function that accepts a redux store instance as an argument and returns a new store with more advanced and easy-to-use subscribe functions to replace the raw subscribe function provided by a Redux store. All subscribe functions return a function that can be called to unsubscribe that subscriber, returning true on success or false if the function had already been unsubscribed.

Example

import { createStore } from 'redux';
import injectSubscribe from 'redux-advanced-subscribe';

const store = injectSubscribe(createStore((state, action) => {
  // some reducer
]));

const {
  subscribeToState,
  subscribeToStateOnce,
  subscribeToKey,
  subscribeToKeyOnce,
  subscribeToEvent,
  subscribeToEventOnce
} = store;

// set up subscribers

export default store;

Function descriptions

Store#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 last state tree and the current state tree, so that you don't have to keep track of references manually.

const unsubscribe = store.subscribeToState((lastTree, currentTree) => {
  if (lastTree.someBranch !== currentTree.someBranch) {
    store.dispatch({ type: 'SOME_EVENT' });
  }
});

Store#subscribeToStateOnce

This function subscribes to state changes and automatically unsubscribes after it has been called once.

Store#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', (lastSomeBranch, currentSomeBranch) => {
  // do something with last branch and new branch
});

const otherUnsubscribe = store.subscribeToKey(['someBranch', 'someOtherBranch'], (lastTree, currentTree) => {
  // do something when either someBranch or someOtherBranch has changed
});

Store#subscribeToKeyOnce

This function has the same behavior as Store#subscribeToKey but will be unsubscribed automatically after the function is called once.

Store#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 last state tree and the current state tree as arguments whenever that event is dispatched.

const unsubscribe = store.subscribeToEvent('SOME_EVENT', (lastTree, currentTree) => {
  // do something with state when SOME_EVENT is dispatched
});

Store#subscribeToEventOnce

This function has the same behavior as Store#subscribeToEvent except it is unsubscribed after the function is called once.

Store#dispatch.mutexDispatch

This function is a property of Store#dispatch and calls the dispatch function with a mutex that ensures that no subscribers will be called as a result of the dispatch. This can be used to avoid infinite recursion in some cases when you only need your reducers to be called and are sure you do not need subscriber side effects, or it can be used for performance reasons when you do not want your subscribers to be executed.

Note: mutexDispatch is a property of dispatch primarily because this enables the function to be accessed from a react-redux container in the mapDispatchToProps function.

store.dispatch.mutexDispatch({
  type: 'SOME_EVENT',
  payload: // some payload
});

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.

Store#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
    });
  });
});

Sometimes, you may find yourself repeatedly merging several state branches together to form a new model from which many components are rendered. If this part of the state tree is large, or the same model is calculated in many components, then it can be extremely expensive to recalculate this model on every dispatch for every component. The solution is to use a computed branch of the state tree. Usage will vary, but as an example, if your computed branch is a combination of two arrays, you might create a reducer for a computed branch that responds to a 'PUSH_COMPUTED_ITEMS' event and use Store#subscribeToKey to subscribe to changes in the primary list, find the array difference of that branch of the current tree and last tree, calculate your new items, and dispatch a 'PUSH_COMPUTED_ITEMS' event. More examples to come.

Author

Raymond Pulver IV

License

MIT

Readme

Keywords

Package Sidebar

Install

npm i redux-advanced-subscribe

Weekly Downloads

0

Version

0.1.3

License

MIT

Last publish

Collaborators

  • ray1191