Skip to content
A JavaScript library for managing application state
TypeScript JavaScript
Branch: master
Clone or download
Latest commit 0e21426 Aug 7, 2019
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
.github chore(common): CHECKOUT-2737 Add initial project files Feb 27, 2018
src fix(core): CHECKOUT-4272 Only create new frozen objects if they are d… Aug 7, 2019
.editorconfig chore(common): CHECKOUT-2737 Add initial project files Feb 27, 2018
.gitignore chore(common): CHECKOUT-3053 Remove lib folder from repository and ad… May 14, 2018
.travis.yml chore(common): CHECKOUT-3053 Remove Yarn May 14, 2018
CHANGELOG.md chore(release): 1.0.1 Aug 7, 2019
LICENSE.md Add MIT license May 9, 2018
README.md docs(common): CHECKOUT-3790 Update docs indentation Jan 8, 2019
commit-validation.json chore(common): CHECKOUT-2737 Add initial project files Feb 27, 2018
jest-config.js chore(common): CHECKOUT-2960 Specify different tsconfig file for release May 14, 2018
jest-setup.js chore(common): CHECKOUT-2737 Add initial project files Feb 27, 2018
package-lock.json chore(release): 1.0.1 Aug 7, 2019
package.json chore(release): 1.0.1 Aug 7, 2019
tsconfig-build.json
tsconfig.json fix(common): CHECKOUT-3191 Fix sourcemaps by enabling `inlineSources` May 27, 2018
tslint.json style(core): CHECKOUT-3053 Fix TSLint issues that are trivial to fix May 7, 2018

README.md

@bigcommerce/data-store

Build Status

A JavaScript library for managing application state.

It helps you to enforce unidirectional data flow in your application, by allowing you to:

  • Subscribe to changes to the application state
  • Update the state in a serial and immutable fashion

Install

You can install this library using npm.

npm install --save @bigcommerce/data-store

Requirements

This library requires Promise polyfill if you need to support older browsers, such as IE11.

You may need to create Observables when using this library (please refer to the usage section). We recommend you to use rxjs until the time comes when you can create them natively.

Usage

Create a store

import { createDataStore } from '@bigcommerce/data-store';

const reducer = (state, action) => {
    switch (action.type) {
    case 'INCREMENT':
        return { ...state, count: state.count + 1 };

    case 'UPDATE_COUNT':
        return { ...state, count: action.payload };

    default:
        return state;
    }
};

const initialState = { count: 0 };
const store = createDataStore(reducer, initialState);

To update the current state

import { createAction } from '@bigcommerce/data-store';

store.dispatch(createAction('INCREMENT'));
store.dispatch(createAction('UPDATE_COUNT', 10)));

To update the state asynchronously, you need to create an observable that emits actions:

import { Observable } from 'rxjs';

const action$ = Observable
    .ajax({ url: '/count' })
    .map(({ response }) => createAction('UPDATE_COUNT', response.count))

store.dispatch(action$);

To avoid race condition, actions get dispatched in a series unless you specify a different dispatch queue, i.e.:

store.dispatch(action$);
store.dispatch(action$);

// The following call does not wait for the previous calls
store.dispatch(action$, { queueId: 'foobar' });

Wrap the observable in a closure if you want to access the store elsewhere but don't have direct access to it (i.e.: inside an action creator):

// In an action creator
function updateAction() {
    return (store) => Observable
        .ajax({ url: '/count' })
        .map(({ response }) => {
            const { count } = store.getState();

            return createAction('UPDATE_COUNT', count + response.count);
        });
}
// In a component
store.dispatch(updateAction());

To do something after an asynchronous dispatch:

const { state } = await store.dispatch(action$);

console.log(state);

To subscribe to changes

To changes and render the latest data:

store.subscribe((state) => {
    console.log(state);
});

The subscriber will get triggered once when it is first subscribed. And it won't get triggered unless there's a data change.

To filter out irrelevant changes:

// Only trigger the subscriber if `count` changes
store.subscribe(
    (state) => { console.log(state); },
    (state) => state.count
);

To transform states and actions

To transform the return value of getState or parameter value of subscribe:

const stateTransformer = (state) => ({ ...state, transformed: true });
const store = createDataStore(reducer, initialState, { stateTransformer });

console.log(store.getState()); // { count: 0, transformed: true }

To transform dispatched actions:

const actionTransformer = (action) => ({ ...action, transformed: true });
const store = createDataStore(reducer, initialState, { actionTransformer });

console.log(store.dispatch(createAction('INCREMENT'))); // { type: 'INCREMENT', transformed: true }

Contribution

To release:

npm run release

To see other available commands:

npm run

License

MIT

You can’t perform that action at this time.