异步 atom

在之前的章节中其实已经出现过了使用异步作为 atom 初始化 read 方法的 atom 示例。这是因为 Jotai 中所有 atom 的创建方法都原生支持使用异步函数作为 atom 的 read 函数和 write 函数。所以异步 atom 的定义与普通 atom 没有什么两样,这里就不再赘述了。

本节所要集中讲述的内容是与异步 atom 相关的一些内容。

异步 atom 的同步使用

jotai/utils里提供了一个loadable函数,可以将一个异步 atom 转换为同步 atom 来使用。loadable的使用非常简单,它就相当于创建 atom 的atom函数,直接套在异步 atom 外面即可。

以下示例展示了loadable的使用方法。

const fetchAtom = atom(async (get) => { ... });
const loadableAtom = loadable(fetchAtom);

const Component = () => {
  const [value] = useAtom(loadableAtom);

  if (value.state === 'loading') {
    return <div>Loading...</div>;
  }
  if (value.state === 'hasError') {
    return <div>Error: {value.error}</div>;
  }
  if (value.state == 'hasData') {
    return <div>{value.data}</div>
  }
}

使用loadable创建的 atom 在使用useAtom获取其内容的时候,返回的是以下类型的内容:

type LoadableAtomValue = {
  state: "loading" | "hasData" | "hasError";
  data?: any;
  error?: any;
};

结合这个类型,就可以知道上面示例中各个判断的含义了。

更加低阶的向同步 atom 转换

Jotai 在转换异步 atom 方面,除了提供了loadable函数以外,还提供了一个unwrap函数。与loadable不一样,unwrap不会自动处理异步过程中出现的错误,而是会将其抛出或者使用fallback函数返回的值代替。unwrap函数的使用与loadable函数基本一致,在使用中只需要参考以下unwrap函数的签名提供相应的参数即可。

// 不提供fallback的版本
function unwrap<Value, Args extends unknown[], Result>(
  atom: Writable<Value, Args, Result>
): WritableAtom<Awaited<Value> | undefined, Args, Result>;

// 提供fallback的用于派生atom的版本
function unwrap<Value, Args extends unknown[], Result>(
  atom: WritableAtom<Value, Args, Result>,
  fallback: (prev?: Awaited<Value>) => PendingValue
): WritableAtom<Awaited<Value> | PendingValue, Args, Result>;

// 提供fallback的用于原始atom的版本
function unwrap<Value, PendingValue>(
  atom: Atom<Value>,
  fallback: (prev?: Aawaited<Value>) => PendingValue
): Atom<Awaited<Value> | PendingValue>;

在以上函数签名中,Awaited<Value>都代表一个异步 atom 的执行结果。