I started to use React Hook a year and a half ago. When I was doing the project, I was thinking whether the reducer method like REdux was too complicated. For example, to write data to the pipeline, we had to call a dispatch method and make a reducer data merge method. With all kinds of middleware, it’s easy to create some painful code.
Redux is essentially a global subscription model
As shown in the figure, REdux provides a subscription pipeline, ComponentA/ComponentB/ComponentC writes data to Redux through dispatch, reducer merges data and saves it to Redux States, The component that subscribes to the data updates in response to changes in the data.
React 16.8 releases hook and useState. Can we introduce a new simplified version to replace Redux?
Global State is a good solution. There are some foreign versions, and I will give mine here.
Just a paragraph like that (^_^)
// global-state.ts
import { useEffect, useState } from 'react';
declare const process: any;
export const GLOBAL_STATE = {
DEBUG: false
};
export const makeGlobalState = <T extends unknown>(initValue: T, name?: string, filter?: (val: T) => T) => {
const globalStates: any[] = [];
let currentValue = initValue;
return (): [T, (val: T) => void] => {
const [value, setValue] = useState(currentValue);
if (!globalStates.includes(setValue)) {
globalStates.push(setValue);
}
useEffect(
() => () => {
if (process.env.NODE_ENV && process.env.NODE_ENV === 'development') {
globalStates.splice(globalStates.indexOf(setValue) - 1, 2);
} else {
globalStates.splice(globalStates.indexOf(setValue), 1);
}
},
[]
);
const setAllStateValue = (value: T) => {
if (filter) {
value = filter(value);
}
if (GLOBAL_STATE.DEBUG) {
console.log('SET ' + name, value);
}
currentValue = value;
globalStates.forEach((setVal) => {
setVal(value);
});
};
return [value, setAllStateValue];
};
};
Copy the code
To refresh all Components, create a collector for the local state of each Component, collect setState methods, and iterate through all set states every time the global state setting method is called.
-
UseEffect is used in the code to remove the setState method when component is destroyed. Note here because component renders twice in Development mode (it adds twice), there is some processing to be done here.
-
The makeGlobalState function also provides a filter function that can do what reducer does with data . The second parameter, name, is used for debug printing.
To use it, create a file that defines all global-states and gives them their initial values.
// my-global-states.ts
import { makeGlobalState } from './global-state';
export const useCounter = makeGlobalState(1.'Counter'.(val) = > {
return val > 10 ? 10 : val;
});
export const useUserInfo = makeGlobalState({ name: 'John'.age: 30 });
Copy the code
It can then be used in different components
// CompA.tsx
import React from 'react';
import { useCounter } from './my-global-states';
export const CompA = () = > {
const [count, setCount] = useCounter();
return (
<div>
<div>{count}</div>
<button
onClick={()= >{ setCount(count + 1); }} > 1</button>
</div>
);
};
Copy the code
// CompB.tsx
import React from 'react';
import { useCounter } from './my-global-states';
export const CompB = () = > {
const [count, setCount] = useCounter();
return (
<div>
<div>{count}</div>
<button
onClick={()= >{ setCount(5); }} > Set it to 5</button>
</div>
);
};
Copy the code
// App.tsx
import React from 'react';
import './App.css';
import { CompA } from './CompA';
import { CompB } from './CompB';
import { GLOBAL_STATE } from './global-state';
GLOBAL_STATE.DEBUG = true;
function App() {
return (
<div className="App">
<div>
<CompA />
</div>
<div>
<CompB />
</div>
</div>
);
}
export default App;
Copy the code
As a result, any component that uses useCounter calls the setCounter method, and any other component that subscribed to the couter value is refreshed.