/unistore

🌶 650b state container with component actions for Preact & React

Primary LanguageJavaScriptMIT LicenseMIT

unistore
npm travis

unistore

A tiny ~650b centralized state container with component bindings for Preact & React.

  • Small footprint complements Preact nicely
  • Familiar names and ideas from Redux-like libraries
  • Useful data selectors to extract properties from state
  • Portable actions can be moved into a common place and imported
  • Functional actions are just reducers

Table of Contents

Install

This project uses node and npm. Go check them out if you don't have them locally installed.

npm install --save unistore

Then with a module bundler like webpack or rollup, use as you would anything else:

// The store:
import createStore from 'unistore'

// Preact integration
import { Provider, connect } from 'unistore/preact'

// React integration
import { Provider, connect } from 'unistore/react'

Alternatively, you can import the "full" build for each, which includes both createStore and the integration for your library of choice:

import { createStore, Provider, connect } from 'unistore/full/preact'

The UMD build is also available on unpkg:

<!-- just unistore(): -->
<script src="//unpkg.com/unistore/dist/unistore.umd.js"></script>
<!-- for preact -->
<script src="//unpkg.com/unistore/full/preact.umd.js"></script>
<!-- for react -->
<script src="//unpkg.com/unistore/full/react.umd.js"></script>

You can find the library on window.unistore.

Usage

import createStore from 'unistore'
import { Provider, connect } from 'unistore/preact'

let store = createStore({ count: 0 })

// If actions is a function, it gets passed the store:
let actions = store => ({
  // Actions can just return a state update:
  increment(state) {
    return { count: state.count+1 }
  },

  // The above example as an Arrow Function:
  increment2: ({ count }) => ({ count: count+1 }),

  //Actions receive current state as first parameter and any other params next
  //check this function as <button onClick={incrementAndLog}>
  incrementAndLog: ({ count }, event) => {
    console.info(event)
    return { count: count+1 }
  },

  // Async actions can be pure async/promise functions:
  async getStuff(state) {
    let res = await fetch('/foo.json')
    return { stuff: await res.json() }
  },

  // ... or just actions that call store.setState() later:
  incrementAsync(state) {
    setTimeout( () => {
      store.setState({ count: state.count+1 })
    }, 100)
  }
})

const App = connect('count', actions)(
  ({ count, increment }) => (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>Increment</button>
    </div>
  )
)

export default () => (
  <Provider store={store}>
    <App />
  </Provider>
)

Debug

Make sure to have Redux devtools extension previously installed.

import createStore from 'unistore'
import devtools    from 'unistore/devtools'

let initialState = { count: 0 };
let store = process.env.NODE_ENV === 'production' ?  createStore(initialState) : devtools(createStore(initialState));

// ...

Examples

README Example on CodeSandbox

API

Reporting Issues

Found a problem? Want a new feature? First of all, see if your issue or idea has already been reported. If not, just open a new clear and descriptive issue.

License

MIT License © Jason Miller