Skip to content

Repository files navigation

unistore
npmtravis

unistore

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

  • Small footprint complements Preact nicely (unistore + unistore/preact is ~650b)
  • 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
  • NEW: seamlessly run Unistore in a worker via Stockroom

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:importcreateStorefrom'unistore'// Preact integrationimport{Provider,connect}from'unistore/preact'// React integrationimport{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(): --><scriptsrc="https://unpkg.com/unistore/dist/unistore.umd.js"></script><!-- for preact --><scriptsrc="https://unpkg.com/unistore/full/preact.umd.js"></script><!-- for react --><scriptsrc="https://unpkg.com/unistore/full/react.umd.js"></script>

You can find the library on window.unistore.

Usage

importcreateStorefrom'unistore'import{Provider,connect}from'unistore/preact'letstore=createStore({count: 0,stuff: []})letactions={// Actions can just return a state update:increment(state){// The returned object will be merged into the current statereturn{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// See the "Increment by 10"-button belowincrementBy: ({ count },incrementAmount)=>{return{count: count+incrementAmount}},}// If actions is a function, it gets passed the store:letactionFunctions=store=>({// Async actions can be pure async/promise functions:asyncgetStuff(state){constres=awaitfetch('/foo.json')return{stuff: awaitres.json()}},// ... or just actions that call store.setState() later:clearOutStuff(state){setTimeout(()=>{store.setState({stuff: []})// clear 'stuff' after 1 second},1000)}// Remember that the state passed to the action function could be stale after// doing async work, so use getState() instead:asyncincrementAfterStuff(state){constres=awaitfetch('foo.json')constresJson=awaitres.json()// the variable 'state' above could now be old,// better get a new one from the storeconstupToDateState=store.getState()return{stuff: resJson,count: upToDateState.count+resJson.length,}}})// Connecting a react/preact component to get current state and to bind actionsconstApp1=connect('count',actions)(({ count, increment, incrementBy })=>(<div><p>Count: {count}</p><buttononClick={increment}>Increment</button><buttononClick={()=>incrementBy(10)}>Increment by 10</button></div>))// First argument to connect can also be a string, array or function while// second argument can be an object or a function. Here we pass an array and// a function.constApp2=connect(['count','stuff'],actionFunctions)(({ count, stuff, getStuff, clearOutStuff, incrementAfterStuff })=>(<div><p>Count: {count}</p><p>Stuff:
<ul>{stuff.map(s=>(<li>{s.name}</li>))}</ul></p><buttononClick={getStuff}>Get some stuff!</button><buttononClick={clearOutStuff}>Remove all stuff!</button><buttononClick={incrementAfterStuff}>Get and count stuff!</button></div>))exportconstgetApp1=()=>(<Providerstore={store}><App1/></Provider>)exportconstgetApp2=()=>(<Providerstore={store}><App2/></Provider>)

Debug

Make sure to have Redux devtools extension previously installed.

importcreateStorefrom'unistore'importdevtoolsfrom'unistore/devtools'letinitialState={count: 0};letstore=process.env.NODE_ENV==='production' ? createStore(initialState) : devtools(createStore(initialState));// ...

Examples

README Example on CodeSandbox

API

createStore

Creates a new store, which is a tiny evented state container.

Parameters

  • stateObject Optional initial state (optional, default {})

Examples

letstore=createStore();store.subscribe(state=>console.log(state));store.setState({a: 'b'});// logs { a: 'b' }store.setState({c: 'd'});// logs { a: 'b', c: 'd' }

Returns store

store

An observable state container, returned from createStore

action

Create a bound copy of the given action function. The bound returned function invokes action() and persists the result back to the store. If the return value of action is a Promise, the resolved value will be used as state.

Parameters

  • actionFunction An action of the form action(state, ...args) -> stateUpdate

Returns Function boundAction()

setState

Apply a partial state object to the current state, invoking registered listeners.

Parameters

  • updateObject An object with properties to be merged into state
  • overwriteBoolean If true, update will replace state instead of being merged into it (optional, default false)
subscribe

Register a listener function to be called whenever state is changed. Returns an unsubscribe() function.

Parameters

  • listenerFunction A function to call when state changes. Gets passed the new state.

Returns Function unsubscribe()

unsubscribe

Remove a previously-registered listener function.

Parameters

  • listenerFunction The callback previously passed to subscribe() that should be removed.
getState

Retrieve the current state object.

Returns Object state

connect

Wire a component up to the store. Passes state as props, re-renders on change.

Parameters

  • mapStateToProps(Function | Array | String) A function mapping of store state to prop values, or an array/CSV of properties to map.
  • actions(Function | Object)? Action functions (pure state mappings), or a factory returning them. Every action function gets current state as the first parameter and any other params next

Examples

constFoo=connect('foo,bar')(({ foo, bar })=><div/>)
constactions={ someAction }constFoo=connect('foo,bar',actions)(({ foo, bar, someAction })=><div/>)

Returns Component ConnectedComponent

Provider

Extends Component

Provider exposes a store (passed as props.store) into context.

Generally, an entire application is wrapped in a single <Provider> at the root.

Parameters

  • propsObject
    • props.storeStore A {Store} instance to expose via context.

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

About

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

Topics

Resources

Code of conduct

Stars

2.8k stars

Watchers

38 watching

Forks

Releases

Packages

Used by

Contributors

Languages