React通过useSyncExternalStore实现一个简单的Redux
useSyncExternalStore
useSyncExternalStore 是一个让你订阅外部 store 的 React Hook。
1const snapshot = useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot?)
2
我们在react中,实现数据共享,无非是三种方式
- props传递或者useContext共享节点内的所有状态
- 使用redux等状态管理库实现全局状态管理
- 通过Event Bus去实现发布订阅
redux或者类似于zustand这种状态管理库他们是如何实现当状态更新而去重新渲染页面的呢?
在它们内部基本上都会维护两个状态,一个是currentState数据源,一个是listeners监听器数组。当我们订阅的时候,会去给监听器数组添加一个监听,当我们去修改数据的时候,再去循环执行监听器的函数,而这个函数就是我们需要想办法去重新render这个组件。 而使用了useSyncExternalStore这个hooks,就相当于为我们写好了这个监听器的函数。
代码实现
1export function CreateStore(reducer: any) {
2 let currentState = null;
3 const listeners = [];
4
5 function getSnapshot() {
6 return currentState;
7 }
8
9 function dispatch(action) {
10 currentState = reducer(currentState, action);
11 listeners.forEach((listener) => listener());
12 }
13
14 function subscribe(listener) {
15 listeners.push(listener);
16 }
17
18 return {
19 getSnapshot,
20 dispatch,
21 subscribe,
22 };
23}
24
25export function useStore() {
26 const storeRef = useRef();
27
28 if (!storeRef.current) {
29 storeRef.current = CreateStore(countReducer);
30 }
31
32 return storeRef.current;
33}
34
35function countReducer(state = 0, action) {
36 console.log(state, action);
37 switch (action.type) {
38 case "ADD":
39 return state + 1;
40 case "MINUS":
41 return state - 1;
42 default:
43 return state;
44 }
45}
46
外部使用
1import { Button } from "@nextui-org/react";
2import { useStore } from "../../store/createStore";
3import { useSyncExternalStore } from "react";
4
5function Index() {
6 const store = useStore();
7 const state = useSyncExternalStore(store.subscribe, store.getSnapshot);
8
9 console.log(state);
10 return (
11 <div className="flex flex-col gap-y-10 items-center justify-center">
12 <Button onClick={() => store.dispatch({ type: "ADD" })}>Add</Button>
13 <Button onClick={() => store.dispatch({ type: "MINUS" })}>MINUS</Button>
14 {state}
15 </div>
16 );
17}
18
19export default Index;
20
相关笔记