EN
React - create shared state across multiple components using custom solution
3 points
Writing applications in React it happens we need to share state between multiple components.
Thare are multiple ways to do it:
This article shows some custom hooks that lets to share state in simple way across multiple components. The motivation to state sharing can be as e.g. authentication, where user may login, logout and current state may be needed in any time and place.
The main advantages of the below solution are:
- very small size
- very good performance
- posibility to read current state in any application lifecycle, what is not provided via React states.
Runnable example is available here.
App.tsx
file:
xxxxxxxxxx
1
import React, {createContext, useContext} from 'react';
2
3
import {useSharedState} from './state';
4
5
const SharedState = createContext();
6
7
const Component1 = () => {
8
const sharedState = useContext(SharedState);
9
return (
10
<div>
11
<button onClick={() => sharedState.setValue('red')}>Set red</button>
12
<button onClick={() => sharedState.setValue('green')}>Set green</button>
13
<button onClick={() => sharedState.setValue('blue')}>Set blue</button>
14
</div>
15
);
16
};
17
18
const Component2 = () => {
19
const sharedState = useContext(SharedState);
20
const sharedValue = sharedState.useValue();
21
return (
22
<div>
23
Shared value: {sharedValue}
24
</div>
25
);
26
};
27
28
const App = () => {
29
const sharedState = useSharedState('default'); // replace 'default' with your default value
30
return (
31
<div className="app">
32
<SharedState.Provider value={sharedState}>
33
<Component1 />
34
<Component2 />
35
<Component2 />
36
<Component2 />
37
</SharedState.Provider>
38
</div>
39
);
40
};
41
42
export default App;
state.tsx
file:
xxxxxxxxxx
1
import {useState, useMemo, useEffect} from 'react';
2
3
export const createSharedState = (value) => {
4
let _value = value;
5
const _listeners = new Array();
6
return {
7
setValue: (value) => {
8
for (const listener of _listeners) {
9
listener(value);
10
}
11
},
12
getValue: () => {
13
return _value;
14
},
15
useValue: () => {
16
const [counter, setCounter] = useState(0);
17
useEffect(
18
() => {
19
const listener = (value) => {
20
_value = value;
21
setCounter(counter => counter + 1);
22
};
23
_listeners.push(listener);
24
return () => {
25
var index = _listeners.indexOf(listener);
26
if (index !== -1) {
27
_listeners.splice(index, 1);
28
}
29
};
30
},
31
[]
32
)
33
return _value;
34
}
35
};
36
};
37
38
export const useSharedState = (value) => {
39
return useMemo(
40
() => createSharedState(value),
41
[value]
42
);
43
};