Dead simple centralized state container (store) with preact and react bindings.
npm install 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
- Install
- Usage
- Examples
- API
- License
This project uses node and npm. Go check them out if you don't have them locally installed.
``sh`
npm install --save unistore
Then with a module bundler like webpack or rollup, use as you would anything else:
`js
// 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:
`js`
import { createStore, Provider, connect } from 'unistore/full/preact'
The UMD build is also available on unpkg:
`html`
You can find the library on window.unistore.
`js
import createStore from 'unistore'
import { Provider, connect } from 'unistore/preact'
let store = createStore({ count: 0, stuff: [] })
let actions = {
// Actions can just return a state update:
increment(state) {
// The returned object will be merged into the current 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
// See the "Increment by 10"-button below
incrementBy: ({ count }, incrementAmount) => {
return { count: count+incrementAmount }
},
}
// If actions is a function, it gets passed the store:
let actionFunctions = store => ({
// Async actions can be pure async/promise functions:
async getStuff(state) {
const res = await fetch('/foo.json')
return { stuff: await res.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:
async incrementAfterStuff(state) {
const res = await fetch('foo.json')
const resJson = await res.json()
// the variable 'state' above could now be old,
// better get a new one from the store
const upToDateState = store.getState()
return {
stuff: resJson,
count: upToDateState.count + resJson.length,
}
}
})
// Connecting a react/preact component to get current state and to bind actions
const App1 = connect('count', actions)(
({ count, increment, incrementBy }) => (
Count: {count}
// 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.
const App2 = connect(['count', 'stuff'], actionFunctions)(
({ count, stuff, getStuff, clearOutStuff, incrementAfterStuff }) => (
Count: {count}
Stuff:
export const getApp1 = () => (
)
export const getApp2 = () => (
)
`
Make sure to have Redux devtools extension previously installed.
`js
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));
// ...
`
#### createStore
Creates a new store, which is a tiny evented state container.
Parameters
- state Object Optional initial state (optional, default {})
Examples
`javascript`
let store = 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
- action Function 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
- update Object An object with properties to be merged into stateoverwrite
- Boolean 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
- listener Function A function to call when state changes. Gets passed the new state.
Returns Function unsubscribe()
##### unsubscribe
Remove a previously-registered listener function.
Parameters
- listener Function 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
`javascript`
const Foo = connect('foo,bar')( ({ foo, bar }) => )
`javascript`
const actions = { someAction }
const Foo = connect('foo,bar', actions)( ({ foo, bar, someAction }) => )
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 at the root.
Parameters
- props Object props.store` Store A {Store} instance to expose via context.
-
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.
[preact]: https://github.com/developit/preact
[react]: https://github.com/facebook/react