useSyncExternalStore

72 阅读1分钟

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两次的问题。

【手写案例】

codesandbox.io/s/usesyncex…