English | 简体中文
Hodux
The reactivity state management for React. Made with ❤️ and ES6 Proxy API.
Inspired by react-easy-state but more friendly for React Hooks.
Features
- Observable store: the state flow is easy enough.
- State selectable: extract state as needed, the components will not re-render unless any selected state changes.
- Perfectly TypeScript support.
Introduction
Hodux is a reactivity state management solution for React which supports both Hooks and Class, it has only 2 core APIs and quit easy to learn.
; // create store(Observable)const counter = ; // select state from store(Dependency collection) { const num = ; // or you can do some compute in component // const total = useSelector(() => counter.num + props.step); return <div onClick=counterinc>The num:num</div>;}
Install
npm install --save hodux# or $ yarn add hodux
API
store(model)
- Signature:
function store<M extends object>(model: M): M
- Description: creates and returns a proxied observable object by the passed model(object), the original model object is not modified. It's just a wrapper of observable().
create store with object-based model:
// stores/counter.jsconst counter = ; ;
lazy creates:
// stores/counter.js { const state = ; { state += n; } { await ; statecount += 1; } return state inc incx }
local store(create store inner components):
Maybe use native APIs(useState or useReducer) will be better, the goal of hodux is shared store between components.
{ const counter = ; const count = ; return <div onClick= countercount++>count</div>;}
useSelector(selector, config?)
- Signature:
function useSelector<V>(selector: Selector<V>, config?: Config<V>): V
- Description: extracts state from store as needed, the components will re-render only if the selected state changes, maybe it's the main difference with react-redux's useSelector(), because react-redux call selector whenever store state changes even not selected at all(react-redux internal decides if makes re-render), so you do't need to use any cache selector library(such as reselect) with useSelector.
useSelector
accepts two parameters:
-
the first parameter is a selector function which works as observer API in reactivity system. It subscribes the selected state and equals the previous returned value with the next one to decide if or not re-render. Maybe you can do some compute with state in useSelector and takes result as the return value.
-
the second is an optional config object
-
equals
: the compare function between previous return value and the next return value, the defalut is equality -
debugger
: the debugger function passed to@nx-js/observer-util
-
Returns basic type is recommended:
;
You should pass in equals function when returns object:
; // use lodash/isEqual
Select state from multiple stores:
{ // whenever the `count` from store1 or the `step` from store1 changes the compoent will re-render, so the `result` is always be the newest value const result = ;}
connect(selector, ownProps?)
A HOC wrapper of useSelector
to connect store state to the class components, and is only for class components.
connect
accepts two parameters:
-
selectorWithProps(ownProps?)
: familiar to selector, but the difference is selectorWithProps must return object type(such asmapStateToProps
in react-redux), selectorWithProps accepts the connected component's props as parameter. -
config
: same as useSelector's config parameter
class component usage:
const counter = ; const selectToProps = n: countern ; { return <div onClick=counterinc>n</div>; } const ReactivedCounter = Counter;
ownProps:
const selectToProps = step: propsstep n: testStoren; Component state = n: thispropsn { const n = thisstaten + thispropsstep; this; } { return <div onClick= this>thisstaten</div>; } const Connected = Counter; ;
<HoduxConfig equals={fn} debugger={fn} />
- Type:
React.FunctionComponent<React.PropsWithChildren<Config<any>>>
- Description: The global config Provider.
{ if etype !== 'get' console; } ReactDOM;
batch(fn)
- Signature:
function batch(fn: Function) => void
- Description: a wrapper of
unstable_batchedUpdates
, to prevent multiples render caused by multiple store mutations in asynchronous handler such assetTimeout
andPromise
, etc. If you experience performance issues you can batch changes manually withbatch
.
NOTE: The React team plans to improve render batching in the future. The
batch
API may be removed in the future in favor of React's own batching.
const listStore = ; listStoreload = async { testStoreloading = true; const list = await ; ;}
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