- Tiny with 0 dependency and simple (less than 1.5kb)
- Persist state by default (
sessionStorage
orlocalStorage
) - Build with React Hooks
- Compatible with React Native
$ npm install little-state-machine
π₯ Demo
This is a Provider Component to wrapper around your entire app in order to create context.
createStore(store, options?: {
name: string; // rename the store
middleWares?: Function[]; // function to invoke each action
syncStores?: // sync with external store in your session/local storage
| Record<string, string[]>
| { externalStoreName: string; transform: Function } // name of the external store, and state to sync
| { externalStoreName: string; transform: Function }[];
}})
Function to initialize the global store, invoked at your app root (where <StateMachineProvider />
lives).
import yourDetail from './state/yourDetail';
function log(store) {
console.log(store);
}
createStore(
{
yourDetail, // it's an object of your state { firstName: '', lastName: '' }
},
{
middleWares: [log], // an array of middleWares, which gets run each actions
syncStores: {
// you can sync with external store and transform the data
externalStoreName: 'externalStoreName',
// alternative you can just specify the store name and root state name { yourDetails: { firstName: '' } }
// externalStoreName: ['yourDetail'],
transform: ({ externalStoreData, currentStoreData }) => {
return { ...externalStoreData, ...currentStoreData };
},
},
// or you can pass in an array of transform function
// syncStores : [
// {
// externalStoreName: 'externalStoreName',
// transform: ({ externalStoreData, currentStoreData }) => {
// return { ...externalStoreData, ...currentStoreData };
// },
// }
// ]
},
);
This hook function will return action/actions and state of the app.
import { updateUserNameAction, removeNameAction } from './actions/yourDetails';
const { action, state } = useStateMachine(updateUserNameAction);
const { actions, state } = useStateMachine({
removeNameAction,
updateUserNameAction,
});
// The following examples are for optional argument
const { action, state } = useStateMachine(updateUserNameAction, {
shouldReRenderApp: false, // This will prevent App from re-render and only update the store
});
π app.js
import React from 'react';
import yourDetail from './yourDetail';
import YourComponent from './yourComponent';
import { StateMachineProvider, createStore } from 'little-state-machine';
import { DevTool } from 'little-state-machine-devtools';
// The following code is for React Native usage
// import { AsyncStorage } from "react-native";
// setStorageType(AsyncStorage);
// create your store
createStore({
yourDetail,
});
export default () => {
return (
<StateMachineProvider>
<DevTool />
<YourComponent />
</StateMachineProvider>
);
};
π yourComponent.js
import React from 'react';
import { updateName } from './action.js';
import { useStateMachine } from 'little-state-machine';
export default function YourComponent() {
const {
action,
state: {
yourDetail: { name },
},
} = useStateMachine(updateName);
return <div onClick={() => action({ name: 'bill' })}>{name}</div>;
}
π yourDetail.js
export default {
name: 'test',
};
π action.js
export function updateName(state, payload) {
return {
...state,
yourDetail: {
...state.yourDetail,
...payload,
},
};
}
DevTool component to track your state change and action.
import { DevTool } from 'little-state-machine-devtools';
<StateMachineProvider>
<DevTool />
</StateMachineProvider>;
For legacy IE11 support, you can import little-state-machine IE11 version.
import { createStore } from 'little-state-machine/dist/little-state-machine.ie11'
Consider adding Object.entries()
polyfill if you're wondering to have support for old browsers.
You can weather consider adding snippet below into your code, ideally before your App.js file:
utils.[js|ts]
if (!Object.entries) {
Object.entries = function( obj ){
var ownProps = Object.keys( obj ),
i = ownProps.length,
resArray = new Array(i); // preallocate the Array
while (i--)
resArray[i] = [ownProps[i], obj[ownProps[i]]];
return resArray;
};
}
Or you can add core-js polyfill into your project and add core-js/es/object/entries
in your polyfills.[js|ts]
file.