useSyncExternalStore是React18中的新特性之一。
React18的beta版本将useMutableSource更新为了useSyncExternalStore,这个新的api将会对React的各种状态管理库产生非常大的影响,本文将介绍useSyncExternalStore的用法和场景
用于订阅一个外部的store,可以自定义一个类型redux的状态管理工具。
const state = useSyncExternalStore(store.subscribe, ()=>store.getSnapshot().data);
第一个参数:订阅函数,当订阅的是state变更后需要执行的方法(比如重绘),dispatch执行完后需遍历订阅函数并执行;
第二个参数:是获取store中state的方法,这里可以直接传store.getSnapshot(),也可以通过()=>store.getSnapshot().data 获取state
使用useSyncExternalStore构建一个状态管理工具
const store = {
currentState: {},
listeners: {},
reducerMap: {},
reducer(nameSpace) {
if (!store.reducerMap[nameSpace]) {
console.error(`无reducer【${nameSpace}】`);
return;
}
return store.reducerMap[nameSpace];
},
subscribe(l, nameSpace) {
if (!store.listeners[nameSpace]) {
store.listeners[nameSpace] = [];
}
// store.listeners[nameSpace].push(l);
store.listeners[nameSpace] = [l];
},
// 获取当前的state
getSnapshot(nameSpace) {
return store.currentState[nameSpace];
},
dispatch(action) {
const [nameSpace] = action?.type?.split("/");
if (!store.reducerMap[nameSpace]) {
console.error(`请检查action的type是否正确,未找到对应的reducer`);
return;
}
const reducer = store.reducer(nameSpace);
if (reducer) {
const preState = store.currentState[nameSpace];
store.currentState[nameSpace] = reducer(preState, action);
store.listeners[nameSpace].forEach((l) => l());
}
return action;
},
addReducer: (nameSpace, reducer, initState) => {
if (store.reducerMap[nameSpace]) {
console.error(`请勿重复天津reducer`);
return;
}
store.reducerMap[nameSpace] = reducer;
store.currentState[nameSpace] = initState;
}
};
export default store;
import { useSyncExternalStore } from "react";
import store from "./";
export default function UseReducer(nameSpace) {
const state =
useSyncExternalStore(
(l) => store.subscribe(l, nameSpace),
() => store.getSnapshot(nameSpace)
) || store.getSnapshot(nameSpace);
console.log("state", state);
const dispatch = store.dispatch;
return { state, dispatch };
}
【缺点】
- 与useReducer一样,存在re-render两次的问题。
【手写案例】