可重置 atom

可重置 atom 是 Jotai 在其核心库基础上扩展出来的一个自带默认功能的 atom。Jotai 在jotai/utils库里定义了一系列相应的构建函数和 Hook 来支持可重置 atom 的使用。

顾名思义,可重置 atom 可以记录其被创建时的初始值,并且可以使用一个特殊值来使 atom 的值恢复为初始值。为了达到这个目的,jotai/utils里定义了一个特殊值RESET,这是一个symbol类型的的值,它存在的唯一目的就是向可重置 atom 传递重置信号。

可重置 atom 时使用jotai/utils中提供的atomWithReset函数构建的,这个函数的使用跟构建 atom 使用的atom函数相像,其签名如下。

function atomWithReset<Value>(
  initialValue: Value,
): WritableAtom<Value, SetStateAction<Value> | type RESET>

可重置 atom 可以像普通 atom 一样通过useAtom Hook 使用。例如:

const TodoListAtom = atomWithReset([]);

const TodoList = () => {
  const [todos, setTodos] = useAtom(TodoListAtom);

  return (
    <div>
      {todos.map((todo, index) => (
        <div key={index}>{todo}</div>
      ))}
      <div>
        <button onClick={() => setTodos(RESET)}>Reset</button>
      </div>
    </div>
  );
};

在这个示例中,通过向 atom 的更新方法传入RESET信号,就可以使 atom 的值恢复到初始值。

为了方便重置操作,Jotai 还提供了一个useResetAtom Hook,可以直接返回一个可重置 atom 的重置方法。现在上面这个示例可以更改为以下形式。

const TodoListAtom = atomWithReset([]);

const TodoList = () => {
  const todos = useAtomValue(TodoListAtom);
  const resetTodoList = useResetAtom(TodoListAtom);

  return (
    <div>
      {todos.map((todo, index) => (
        <div key={index}>{todo}</div>
      ))}
      <div>
        <button onClick={() => resetTodoList()}>Reset</button>
      </div>
    </div>
  );
};

带有默认值的 atom

带有默认值的 atom 是可重置 atom 的一个延伸使用方式。带有默认值的 atom 使用atomWithDefault函数创建,其创建形式与只读 atom 的创建十分相似。带有默认值的 atom 可以基于另一个原始 atom 创建它的初始值,并且在没有更新它的值的情况下,其值会随着它所依赖的原始值变化。但是如果调用了它的更新方法,它将与其依赖的 atom 解耦,直到它被重置为止。

以下是带有默认值的 atom 使用示例,读者可以自行尝试其执行效果。

const counter1Atom = atom(1);
const counter2Atom = atomWithDefault((get) => get(counter1Atom) * 3);

const Demo = () => {
  const [c1, setCounter1] = useAtom(counter1Atom);
  const [c2, setCounter2] = useAtom(counter2Atom);

  return (
    <div>
      <div>Counter 1: {c1}</div>
      <div>Counter 2: {c2}</div>
      <div>
        <button onClick={() => setCounter1((c) => c + 1)}>
          Increment Counter 1
        </button>
        <button onClick={() => setCounter2((c) => c + 3)}>
          Increment Counter 2
        </button>
        <button onClick={() => setCounter2(RESET)}>Reset Counter 2</button>
      </div>
    </div>
  );
};

带有默认值的 atom 同样可以使用useResetAtom来创建快速重置方法。