I am currently working on a simple web application with Next.js.
Though it is simple, there are some states that I wanted to use globally.
Currently there are several approaches to manage global state.
- Redux or Mobx
- Pass
state
andsetState
fromuseState
to child components using React Context - Use react-first global state management libraries (e.g., reactn)
When it comes to global state management in React, Redux is one of the most widely used library. However it is too much for my simple use case because you have to define action creators with action type and payload.
Using React Context or global state management libraries seems much simpler. But one thing that I feel clumsy about these methods is you pass a (part of) state object to setState
or whatever state setter function you use. This means that a caller must know the internal structure of state object. Typically these functions are called inside components. But I don't think components should be aware of the internal.
Wouldn't it be nice if a component can call a method with some parameters to update a global state not knowing the detail?
In a micro-framework called hyperapp
, you can update a state with actions.
An action takes the form of
const someAction = (prevState, arg1, ..., argN) => {/* return newState */}
To the best of my knowledge, however, I could not find any library that does something like hyperapp. So I created react-state-action-hooks
(I know... the name is a bit lengthy...)
Quick Introduction
First, define an initial state and action definitions.
Each key in action definitions maps to an action definition.
Action definition is a function that is somewhat similar to hyperapp action, except that it is a function that returns another function.
The parameters of the outer function are the ones of an action that is generated from the corresponding action definition.
The parameters of returned function are previous state and actions.
As shown in the example below you can either return a new state from previous state or call other actions.
const initialState = {
count: 0,
};
const actionDefs = {
incrementBy: (delta) => (state) => ({
...state,
count: state.count + delta,
}),
decrementBy: (delta) => (state, actions) => {
actions.incrementBy(-1);
},
};
Having prepared initial state and action definitions, you can pass these to useActionState to get state
and actions
!
All the action definition turn into actions, and each of them is a function (not a function that returns a function). And you can call an action with the parameters of the outer function in an action definition.
This way, you don't have to be aware of the internal structure of the state.
const Counter = () => {
const { state, actions } = useActionState(
initialState,
actionDefs
);
return (
<div>
<span>{state.count}</span>
<button onClick={() => {actions.incrementBy(1);}}>
+1
</button>
<button onClick={() => {actions.decrementBy(1);}}>
-1
</button>
</div>
);
};
In the example above, the hook is called in a component but you can use React hook to make it global! Moreover, it fully supports typescript!
For more information, take a look at the documentation.
Pull requests are very welcome!
Top comments (0)