- Notifications
You must be signed in to change notification settings - Fork13
Tiny flux implementation built on mitt
License
tkh44/smitty
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
Tiny flux implementation built onmitt
- Install
- Basic Usage
- Demos
- Usage with Preact and React
- API
- Store
- Action Creator Detailed Example
- Class As Reducer
npm install -S smitty
import{createStore}from'smitty'// Create a store with initial stateconstinitialState={count:0}conststore=createStore(initialState)store.createActions({add:'count/ADD'})// add a reducerstore.handleActions({[store.actions.add]:(state,e,type)=>{// increment foos by amountreturnObject.assign({},state,{count:state.count+e.amount})},'*':(state,e,type)=>{// '*' can be used for all kinds of fun stuffconsole.log(e,type)if(type==='count/ADD'){//...do something}returnstate}})store.actions.add({amount:5})console.log(store.state)// logs `{ count: 5 }`
- Photo BoothDemonstrates async api and saving parts of the store withlocalforage
- Basic
- Async
- Fun
Preact bindings -preact-smitty
npm install preact-smitty
React bindings -react-smitty
npm install react-smitty
initialState: any
required: Determines the shape and initial state of your store. Can be of any type that you choose.
Store: Store
Store
arguments
type: (string |function)
[string],
type
determines which reducers are called.conststore=createStore(0)store.handleActions({add:function(state,payload){returnstate+payload}})console.log(store.state)// logs 0store.emit('add',1)console.log(store.state)// logs 1
[function]
type
becomes an action creator that is passed 1 argument- store:Store
This is useful to emit multiple actions from a single emit call.
conststore=createStore(0)store.handleActions({add:function(state,payload){returnstate+payload}})functionasyncAction(emit,state){emit('add',1)console.log(state)// logs 1setTimeout(()=>{emit('add',1)console.log(state)// logs 3},100)emit('add',1)console.log(state)// logs 2}```
payload: (any) optional
payload to pass to your reducer
conststore=createStore({name:'Arrow'})store.handleActions({'update/NAME':function(state,payload){// I really don't care if you return a new state// Nobody is judging. Do what your ❤️ tells you.// Just be consistentreturnObject.assign({},state,payload)}})console.log(store.state)// logs { name: 'Arrow' }store.emit('update/NAME',{name:'River'})console.log(store.state)// logs { name: 'River' }
arguments
actionMap: (object)
Object where key is the action creator's name and the value can be of typestring
orfunction
.
If the value is astring
, an action creator is attached tostore.actions
as a function that accepts one argument,payload
.
store.createActions({add:'count/ADD'})// The following are functionally equivalentstore.actions.add(1)store.emit('count/ADD',1)
Action creators with a string value can be used as the key in youractionMap
inhandleActions
.
store.createActions({add:'count/ADD'})// add a reducerstore.handleActions({[store.actions.add]:(state,e,type)=>{// increment foos by amountreturnObject.assign({},state,{count:state.count+e.amount})}})store.actions.add({amount:5})console.log(store.state)// logs `{ count: 5 }`
If the value is afunction
, it must be a function that returns an action creator. For async action creators.
store.createActions({add:(amount)=>{return(store)=>{setTimeout(()=>{store.emit('count/ADD',amount)},16)}}})store.actions.add(1)
arguments
handlerMap: (object)
Object with keys that correspond to action types passed toemit
When an event is emitted and the key matches the type the reducer is invoked with 3 arguments.
- state: (any) the store's state getter
- payload (any) the payload that was emitted
- type (string) the type that was emitted
conststore=createStore({color:'blue',hovered:false})store.handleActions({'merge':function(state,payload){returnObject.assign({},state,payload)},'overwrite':function(state,payload){returnpayload},// Could do the same in one// If you really miss redux do this and put a switch statement'*':function(state,payload,type){returntype==='merge' ?Object.assign({},state,payload) :payload}})console.log(store.state)// logs { color: 'blue', hovered: false }store.emit('merge',{color:'red'})console.log(store.state)// { color: 'red', hovered: false }store.emit('overwrite',{color:'green',hovered:true,highlighted:false})console.log(store.state)// { color: 'green', hovered: true, highlighted: false
Map of all the actions created instore.createActions
This is convenient so that you do not have to deal with action imports across your app.
Convenience shortcut formitt.on.
Convenience shortcut formitt.off.
You can pass a function toemit
in order to create an action creator
import{createStore}from'smitty'// Create a store with initial stateconstinitialState={}conststore=createStore(initialState)// add our reducerstore.handleActions({'api/GET_ROOM':(state,{ id, res})=>{return{ ...state,[id]:{ ...state[id], ...res.data}}}})// create our action creatorsconstactions={requestRoom(id){returnasync(emit,state)=>{emit('REQUEST_ROOM',{ id,res:{data:{ id}}})constres=awaitwindow.fetch(`https://api.mysite.com/${id}`)res.data=awaitres.json()emit('REQUEST_ROOM',{ id, res})}}}// When calling emit with a function argument, the function will be called with `emit` and `state` as argumentsconstresult=store.emit(actions.requestRoom('1a'))// Return whatever you like from your action creatorconsole.log(result)// logs "Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}"// After the fetch call, `REQUEST_ROOM` is fired a second time with our response dataresult.then(()=>console.log(store.state))// logs `{ 1a: { id: '1a', title: 'My Room' }``
Reducers are iterated withfor (let type in reducer) {...}
with noobj.hasOwnProperty
check so this works.
conststore=createStore({foo:5})classHistoryReducer{constructor(initialHistory=[]){this.history=createStore(initialHistory)this.history.handleActions({update:(state,e)=>{state.push(e)}})}onUpdate(state,e,type){this.history.emit('update',{ state, e, type})}}HistoryReducer.prototype['foo/ADD']=function(state,e,type){state.foo+=e.foothis.onUpdate(state,e,type)}consthistoryReducer=newHistoryReducer([])store.handleActions(historyReducer)store.emit('foo/ADD',{foo:5})console.log(store.state.foo)// logs 10store.emit('foo/ADD',{foo:7})console.log(store.state.foo)// logs 17console.log(historyReducer.history.state)// logs// [// { state: { foo: 10 }, e: { foo: 5 }, type: 'foo/ADD'},// { state: { foo: 17 }, e: { foo: 7 }, type: 'foo/ADD'}// ]
About
Tiny flux implementation built on mitt