State Management With React Hooks No Redux or Context Api 8b3035ceecf8
State Management With React Hooks No Redux or Context Api 8b3035ceecf8
useState()
Before Hooks, functional components had no state. Now, with the
useState() , we can do it.
It works by returning an array. The �rst item of the above array is a
variable that gives access to the state value. The second item is a
function that updates the state of the component to re�ect the new
values on the DOM.
By default, e�ects run after every completed render. But, you can
choose to �re it only when certain values have changed, passing an
array of variables as a second optional parameter.
. . .
•
Sharing states
We can see that Hooks states works exactly like class component states.
Every instance of the component has its own state.
The idea is to create an array of listeners and only one state object.
Every time that one component changes the state, all subscribed
components get their setState() functions �red and get updated.
use-global-hook
To use it on a component:
1 import React from 'react';
2 import useCustom from './customHook';
3
4 const Counter = () => {
5 const [globalState, setGlobalState] = useCustom();
6
7 const add1Global = () => {
8 const newCounterValue = globalState.counter + 1;
9 setGlobalState({ counter: newCounterValue });
10 };
11
12 return (
13 <div>
14 <p>
15 counter:
16 {globalState.counter}
17 </p>
18 <button type="button" onClick={add1Global}>
19 +1 to global
20 </button>
21 </div>
22 );
23 };
24
25 export default Counter;
This �rst version already works sharing state. You can add as many
Counter components as you want in your application and it will all
have the same global state.
But we can do better
What I didn’t like in this �rst version:
I want to remove the listener from the array when the component
is unmounted.
This is the perfect place to remove the component from the listeners
array.
parameter.
Create a store object that contains the state value and the
setState() function.
The best way is to separate the business logic by creating actions which
manipulate the state. For that reason I want that the last version of our
solution doesn’t give component access to the setState() function,
but a set of actions.
Actions will have access to the store object. For that reason,
actions may read the state with store.state , write state through
store.setState() and even call other actions using
state.actions .
hook .
1 function setState(newState) {
2 this.state = { ...this.state, ...newState };
3 this.listeners.forEach((listener) => {
4 listener(this.state);
5 });
6 }
7
8 function useCustom(React) {
9 const newListener = React.useState()[1];
10 React.useEffect(() => {
11 this.listeners.push(newListener);
12 return () => {
13 this.listeners = this.listeners.filter(listener
14 };
15 }, []);
16 return [this.state, this.actions];
17 }
18
19 function associateActions(store, actions) {
20 const associatedActions = {};
21 Object.keys(actions).forEach((key) => {
22 if (typeof actions[key] === 'function') {
23 associatedActions[key] = actions[key].bind(null, store);
24 }
25 if (typeof actions[key] === 'object') {
26 associatedActions[key] = associateActions(store, actions[key]);
27 }
28 });
29 return associatedActions;
30 }
31
32 const useGlobalHook = (React, initialState, actions) =>
33 const store = { state: initialState, listeners: [] };
34 store.setState = setState.bind(store);
35 store.actions = associateActions(store, actions);
36 return useCustom.bind(store, React);
37 };
38
39 export default useGlobalHook;