English | 简体中文
hookstore
Hook based and lightweight centralized state management for React.
Try it on codesandbox
Features
- Minimal(only 5 APIs) and simplified API: easy to learn(5 minutes about), no
reducer
,dispatch
oreffects
in Redux/dva, onlyaction
which is just normal function withasync/await
support. - Centralized state management and multiple models:
model
is just normal javascript object,state
insideaction
(andmiddleware
)is mutatable for understanding while immutatable inside components(follow the design of React's unidirectional data flow). - Performance optimized:
useStore
api is inspired by react-redux-hooks useSelector, the preformance issue caused by useContext is controlled, only component(s) which useduseStore
hook will be re-rendered when state changed. - Built-in action status listening: Listening
pending
anderror
status of (async)action and update to DOM in real time when action's status change. - koa style middleware system
Install
$ npm install hookstore -S# or $ yarn add hookstore
Usage
Please check out all examples in the examples folder.
1. model(s) definition
// src/models/count.js name: 'count' state: count: 0 actions: { const state = thisctx; statecount += n; } async { const state = thisctx; await { ; }; statecount += n; } { const state actions = thisctx; statecount += n; actions; // await actions.asyncAdd(n); // use async/await can access asyncAdd() response }
2. model(s) initialization
; ;; ; ReactDOM;
3. Access state and actions in child components
// src/components/Counter.js; { const count actions = ; return <div> Math <div> <div>Count: count</div> <button onClick= actions>add 1</button> <button onClick= actions>add 1 and async add 1</button> </div> </div> ;}
API
<Provider models>
The Provider
has to be put in the parent component, and maybe Provider
as root component is recommended.
const Root = <Provider models= model1 model2 > ... </Provider>; ReactDOM;
useStore(name, selector?: Function, equalityFn?: Function) => [ selectedState, actions ]
useStore
integrated the useSelector
and useDispatch()
Apis in react-redux v7.x, it returns the latest state in store and the collect of actions methods(which can safely modify store's state) by tuples.
- name: The name of model
- selector: Pure function with which can extract data from store, the default value is
(state) => state
which will returns the state object in store.It's highly recommended to pass inselector
to select state in need, components will re-render only if the selected keys changes. - equalityFn: the default value is the same as
connect
of react-redux, optional comparison function also enables using something like Lodash's_.isEqual()
.
const Component = { const name actions = ; const nested actions = ; // ...};
useStatus(name/action) => { pending: boolean, error: Error }
useStatus
hook listens the execution status of (asynchronous)actions in real time, and all components used useStatus
hook will receive the actions status update and then render to the DOM.
// src/components/CounterWithLoading.js; const CounterWithLoading = { const count actions = ; const pending error = ; const asyncAdd = { if pending return console; actions; }; return <div> Math <div> pending && <div>loading...<div> error && <div>errormessage<div> <div>count: count</div> <button onClick=asyncAdd>async add 5</button> </div> </div> ;};
getStore(name, selector?: Function) => [ selectedState, actions ]
The params and returns of getStore
is the same as useStore
, the difference is that getStore
is not a React Hook, it;'s just a normal function, so the usage of getStore
is not restricted by Hook Rules(maybe outside of React components), but you should known that useStore
can not listen the changes of state, you should call useStore
again to get the lastest state.
// models/foo.js; name: 'foo' actions: const barActions = ; // access actions from `bar` model // ...
applyMiddlewares([middleware1, middleware2, ...])
Appling koa-style middleware to all of the actions.
;;; ;; ;; { ; return <Provider models= countModel listModel > <h2>Counter</h2> <Counter /> <Counter /> <h2>List</h2> <List /> </Provider> ;} ReactDOM;
custom middleware:
// middlewares/errHandler.js { try await ; catche console; } // use middleware; { ; return <Privider model=model> // ... </Privider> ;}
model(s) definition
model
is just normal javascript object:
example:
// src/models/foo.js name: 'foo' // model name actions: { thisctxstatename = newName; } async { await ; thisctxstatename = newName; }
ctx
The The ctx
store some intermediate states and methods which can only access inside of actions and middlewares.
Type definition:
Run examples locally
The examples folder contains working examples. You can run one of them with
$ cd examples/[folder] && npm start
then open http://localhost:3000 in your web browser.
License
MIT