:::info 🧾 目前处于草稿阶段 :::

Recoil 非常适合用于需要精心编排状态的应用场景,其写法比较简单,天然支持 Hooks,非常 React,且在 React18 之后支持 Transition 的新特性。

Recoil 的核心概念:https://recoiljs.org/docs/introduction/core-concepts

  • Atom:原子化的状态,可以被全局共享和使用
  • AtomEffects:处理状态变化的 SideEffects
  • Selector:类似于 Redux Selector(Reducer) 和 MobX @Computed 的结合体

:::info 😎 将部分应用状态(ClientState)交给 Recoil,将服务端数据状态交给 React Query 最佳实践 就舒服了。
可以参阅:React 应用状态管理随记 :::

https://youtu.be/_ISAA_Jt9kI 👈 这个 Youtube 视频入门非常好。

:::success 💎 👇 这张图基本上概括了 Recoil 的设计思想,铺平的状态,映射到每一个子节点上,且可以 SHARE。
image.png :::

使用全局 SnapShot 打印整体状态

https://recoiljs.org/docs/api-reference/core/Snapshot

  1. class Snapshot {
  2. retain(): () => void;
  3. isRetained(): boolean;
  4. // Accessors to inspect snapshot state
  5. getLoadable: <T>(RecoilValue<T>) => Loadable<T>;
  6. getPromise: <T>(RecoilValue<T>) => Promise<T>;
  7. // API to transform snapshots for transactions
  8. map: (MutableSnapshot => void) => Snapshot;
  9. asyncMap: (MutableSnapshot => Promise<void>) => Promise<Snapshot>;
  10. // Developer Tools API
  11. getID: () => SnapshotID;
  12. getNodes_UNSTABLE: ({
  13. isModified?: boolean,
  14. } | void) => Iterable<RecoilValue<mixed>>;
  15. getInfo_UNSTABLE: <T>(RecoilValue<T>) => {...};
  16. }

可以按需打印,可以在每一次变化的时候均打印全量或者按需打印即可。

增加 Logger 机制

为了让 Recoil 支持类似 Redux-Logger,让每一次 State 变化可追溯,我们可以在 useRecoilState 上做一层封装,打印出变更日志。

import { RecoilState, SetterOrUpdater, useRecoilState } from 'recoil';
import diff from 'diff';

export function useRecoilStateWithLog<T>(
  recoilState: RecoilState<T>,
  entity?: Function,
): [T, SetterOrUpdater<T>] {
  const [state, setter] = useRecoilState(recoilState);
  if (process.env.NODE_ENV === 'development') {
    return [
      state,
      (u) => {
        // 便于察觉变更的日志机制
        // 类似于 Redux-Logger 的实现
        // 提供对象的 diff 能力
        console.groupCollapsed(
          `[Recoil] set state [${recoilState.key}] with action from [${
            entity?.name || entity?.toString() || 'unknown'
          }]`,
        );
        if (typeof u === 'object') {
          console.log('diff: ', diff(state as any, u as any));
        }
        console.trace('update to', u);
        console.groupEnd();
        if (setter) return setter(u);
        return u;
      },
    ];
  } else {
    return [state, setter];
  }
}

image.png
最终实现在开发环境下,调用栈和状态 diff 的输出。

结合 React18 的 Transistion 特性

:::info 🛑 待 R18 发布之后再玩,现在太早了 … :::

Ref:https://recoiljs.org/blog/2022/01/28/0.6.0-release#react-18

Ref