useSyncExternalStore
useSyncExternalStore 是一个让你订阅外部 store 的 React Hook。
const snapshot = useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot?)
我们在react中,实现数据共享,无非是三种方式
- props传递或者useContext共享节点内的所有状态
- 使用redux等状态管理库实现全局状态管理
- 通过Event Bus去实现发布订阅
redux或者类似于zustand这种状态管理库他们是如何实现当状态更新而去重新渲染页面的呢?
在它们内部基本上都会维护两个状态,一个是currentState数据源,一个是listeners监听器数组。当我们订阅的时候,会去给监听器数组添加一个监听,当我们去修改数据的时候,再去循环执行监听器的函数,而这个函数就是我们需要想办法去重新render这个组件。 而使用了useSyncExternalStore这个hooks,就相当于为我们写好了这个监听器的函数。
代码实现
export function CreateStore(reducer: any) {
let currentState = null;
const listeners = [];
function getSnapshot() {
return currentState;
}
function dispatch(action) {
currentState = reducer(currentState, action);
listeners.forEach((listener) => listener());
}
function subscribe(listener) {
listeners.push(listener);
}
return {
getSnapshot,
dispatch,
subscribe,
};
}
export function useStore() {
const storeRef = useRef();
if (!storeRef.current) {
storeRef.current = CreateStore(countReducer);
}
return storeRef.current;
}
function countReducer(state = 0, action) {
console.log(state, action);
switch (action.type) {
case "ADD":
return state + 1;
case "MINUS":
return state - 1;
default:
return state;
}
}
外部使用
import { Button } from "@nextui-org/react";
import { useStore } from "../../store/createStore";
import { useSyncExternalStore } from "react";
function Index() {
const store = useStore();
const state = useSyncExternalStore(store.subscribe, store.getSnapshot);
console.log(state);
return (
<div className="flex flex-col gap-y-10 items-center justify-center">
<Button onClick={() => store.dispatch({ type: "ADD" })}>Add</Button>
<Button onClick={() => store.dispatch({ type: "MINUS" })}>MINUS</Button>
{state}
</div>
);
}
export default Index;