redux-shunt
TypeScript icon, indicating that this package has built-in type declarations

0.0.5 • Public • Published

Redux Shunt

Version Coverage Build Status

Redux shunt is a store enhancer which prevents the store's state from updating when an action is dispatched to it. Instead, both the action and the result of the reducers processing that action (what would have been the new state) are provided to a callback.

Additionally, redux shunt exposes an additional method on the store, setState, which sets the store's entire state tree and notifies its listeners.

Installation:

npm install --save redux-shunt

Why Do I Need This?

Redux shunt breaks your redux store, so if you use it haphazardly you will most likely be disappointed!

The use-case for redux shunt is when you want to encapsulate an entire redux store, and use something else (like another redux store) as its source of truth.

Example usage

Let's say for example we have a redux app, SubApp, which has a simple state tree:

interface SubAppState {
    foo: boolean;
    bar: boolean;
}

Say we have another redux app, MainApp, in which we want to incorporate SubApp:

interface MainAppState {
    baz: boolean;
    subAppState: SubAppState;
}
 
const mainAppInitialState = {
    baz: true;
    subAppState{
        foo: true,
        bar: true
    }
}

Additionally, we want baz of MainApp's state to always be equal to bar from SubApp and vice versa. Other than that, don't really want to worry about SubApp's internals.

Assuming we have an action "SUB_APP_UPDATE" which provides SubApp's new state as the payload each time it should be updated, we can write our reducer for MainApp like this:

const mainAppReducer = (state: MainAppState, action: AnyAction) => {
    switch (action.type) {
        case 'SUB_APP_UPDATE':
            return {
                baz: action.payload.bar,
                subAppState: action.payload
            };
        case 'TOGGLE_BAZ':
            return {
                baz: !state.baz,
                subAppState: { ...state.subAppState, bar: !state.baz }
            };
        default:
            return state;
    }
}

The problems here are:

  1. How do we dispatch an action to MainApp each time SubApp's state should update?
  2. How do we ensure that MainApp takes full responsibility for the state of SubApp, and becomes its source of truth?

This is where redux shunt comes in!

We can shunt updates to SubApp's state so that they are processed through MainApp like so:

import { createStore } from 'redux';
import shunt from 'redux-shunt';
import { subAppReducer } from './subApp/internals/dontknow/dontcare';
 
// create normal store for the main app
const mainAppStore = createStore(mainAppReducer, mainAppInitialState);
 
// sub app's initial state comes from the main app's state tree
const subAppInitialState = mainAppStore.getState().subAppState;
 
// create a shunted store for the sub app, providing a callback to handle state updates
const subAppStore = shunt<SubAppState>(recipient)(createStore)(subAppReducer, subAppInitialState)
 
// refer to the real source of truth (MainApp) for the sub app's state
mainAppStore.subscribe(updateSubApp);
 
function recipient(action: AnyAction, state: SubAppState) {
    // lift the new sub app state into the main app's state tree
    mainAppStore.dispatch({
        type: 'SUB_APP_UPDATE',
        payload: state
    });
}
 
function updateSubApp() {
    const newSubAppState = mainAppStore.getState().subAppState;
 
    // sub app's state is only really updated, and its listeners notified, when the state changes in MainApp
    subAppStore.setState(newSubAppState);
}

That's it! SubApp is now a component of MainApp, and MainApp's store is our single source of truth. Later you can follow the same pattern to use MainApp as a component of an even larger app.

Contributions

Anyone is welcome to contribute to this package. My only "rule" is that your contribution must either pass the existing unit tests, or include additional unit tests to cover new functionality.

Here are some commands that may be helpful for development:

  • npm test: Runs the unit tests
  • npm run build: Builds the library

License

MIT

Package Sidebar

Install

npm i redux-shunt

Weekly Downloads

9

Version

0.0.5

License

MIT

Unpacked Size

21.4 kB

Total Files

10

Last publish

Collaborators

  • nicksenger