Skip to content

mutebg/WorkerStore

Repository files navigation

Worker-Store

1kb state container running inside WebWorker. A similar idea to Redux, besides the action-reducers run inside WebWorker. To do that, dispatch sends only the name of the actions and payload.

Offload expensive work to a WebWorker might improve significant performance. While Main ( UI ) thread can be blocked from expensive operations, the WebWorker solves that like messaging results ( state ) of the operations to UI thread.

Examples

React example

Live demo

Installation

npm install --save worker-store

Documentaion

API documentation

Usage

You need worker loader, something like https://github.com/webpack-contrib/worker-loader

In your app.js

import { createStore } from 'worker-store';
import { Provider, connect  } from 'worker-store/react';
import Worker from './store.worker.js';

// initial store state
const initState = {count: 0, news: []};

// create store
const store = createStore( initState , new Worker() );

// Select state from the store
const mapStateToProps = ( state, ownProps) => ({
    count: state.count,
    news: state.news,
});

//Connects React/Preact component to the store.
const App = connect(mapStateToProps)(({count, news, dispatch}) => {
  return (
    <div>
      <h1>{count}</h1>
      <button onClick={ () => dispatch('inc')}>+1</button>
      <button onClick={ () => dispatch('dec')}>-1</button>
      <button onClick={ () => dispatch('fetch', 5)}>fetch news</button>
      <button onClick={ () => dispatch('generator')}>generator</button>
    </div>
  )
});

// Makes the store available to the connect() calls in the component hierarchy below.
export default () => (
  <Provider store={store}>
    <App />
  </Provider>,
)

Inside your web worker: store.worker.js

import { runStore, put } from "worker-store/worker";

// runStore receive objet of actions
// every action receive current state as first parameter
// and rest as parameters from dispatch function
// action must return the next state  or part of it
runStore({
  inc: state => ({ count: state.count + 1 }),
  dec: state => ({ count: state.count - 1 }),

  // can return Promise which resolves into next state
  fetch: (state, payload) =>
    fetch("https://jsonplaceholder.typicode.com/posts/" + payload)
      .then(res => res.json())
      .then(json => ({ news: json })),

  // or generator function which yield next state
  generator: function*(state) {
    try {
      // using yield and put to update the state
      yield put({ status: "loading" });
      const response = yield fetch(
        "https://jsonplaceholder.typicode.com/posts/1"
      );
      const news = yield response.json();
      yield put({ news: news, status: "done" });
    } catch (err) {
      yield put({ status: "loaded", error: true });
    }
  }
});

Debug

You can use kuker to debug state and actions, very similar way redux-dev-tools does

store.subscribe(({ state, action }) => {
  window.postMessage(
    {
      kuker: true,
      type: "change state",
      origin: "none",
      label: action,
      time: new Date().getTime(),
      state: state
    },
    "*"
  );
});

Inspiration

Inspired by https://github.com/developit/unistore https://github.com/developit/stockroom

LICENSE

MIT

About

Small React state container running inside WebWorker

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published