Skip to content
文档
高级
理解 SWR

理解 SWR

状态机制

useSWR 会根据 fetcher 函数的状态返回 dataerrorisLoadingisValidating。以下这些图片描述了 SWR 在不同情况下是如何返回值的。

请求与重新请求

这种模式表示请求数据,并在之后重新请求的场景。

A pattern for fetch and revalidate

Key 的变化

这种模式表示在请求数据,再改变 key 值,并在之后重新请求的场景。

A pattern for key change

Key 的变化 + 保留之前的数据

这种模式表示在开启 keepPreviousData 选项时,请求数据,再改变 key 值,并在之后重新请求的场景。

A pattern for key change + previous data

设置预设数据

这种模式表示设置了预设数据时,请求数据,并在之后进行重新请求的场景。

A pattern for fallback

Key 的变化 + 设置预设数据

这种模式表示在设置预设数据时,请求数据,再改变 key 值,并在之后进行重新请求的场景。

A pattern for key change + fallback

Key 的变化 + 保留之前的数据 + 设置预设数据

这种模式表示在开启 keepPreviousData 选项并设置预设数据时,请求数据,再改变 key 值,并在之后进行重新请求的场景。

A pattern for key change + previous data + fallback

结合 isLoadingisValidating 以获得更好的用户体验

相比于现有的 isValidatingisLoading 是一个新的属性,它可以帮助我们应对更加普遍的用户加载场景。

  • 无论数据是否已加载,只要有一个正在进行中的请求,isValidating 都会变为 true
  • 当数据尚未加载并且有一个正在进行的请求时,isLoading 会变为 true

简而言之,我们可以使用 isValidating 来表示每次正在进行的重新请求;使用 isLoading 来表示 SWR 正在重新请求中,但目前还没有数据可以展示。

📝

预设数据(Fallback Data)和之前的数据(Previous Data)不会被认为是“已加载的数据”,因此在设置了预设数据或启用 keepPreviousData 选项时,你可能有数据要展示。

function Stock() {
  const { data, isLoading, isValidating } = useSWR(STOCK_API, fetcher, {
    refreshInterval: 3000
  });
 
  // 如果初始数据仍在加载,这里将不展示任何内容。
  // 我们在这里返回一个骨架屏。
 
  if (isLoading) return <div className="skeleton" />;
 
 
  // 否则展示响应数据和一个表示后台正在重新请求的加载器。
  return (
    <>
      <div>${data}</div>
      {isValidating ? <div className="spinner" /> : null}
    </>
  );
}

An example of using the isLoading state

点击 这里 (opens in a new tab) 查看完整代码示例。

返回之前的数据以获得更好的用户体验

在用户连续操作的情况下进行数据请时,例如输入时实时搜索,保留之前的数据可以极大提升用户体验,keepPreviousData 选项可以用于启用该行为。下例是一个简单的用户搜索界面:

function Search() {
  const [search, setSearch] = React.useState('');
 
  const { data, isLoading } = useSWR(`/search?q=${search}`, fetcher, {
    keepPreviousData: true
  });
 
  return (
    <div>
      <input
        type="text"
        value={search}
        onChange={(e) => setSearch(e.target.value)}
        placeholder="Search..."
      />
 
      <div className={isLoading ? "loading" : ""}>
        {data?.products.map(item => <Product key={item.id} name={item.name} />)
      </div>
    </div>
  );
}

如果启用了 keepPreviousData,即使我们改变了 SWR key 值并以新的 key 值重新开始加载,我们仍然可以保留之前的数据。

当启用 keepPreviousData 时,保留上一次搜索的结果

在这里查看完整代码示例:https://codesandbox.io/s/swr-keeppreviousdata-fsjz3m。 (opens in a new tab)

性能依赖关系收集

SWR 只会在组件中所使用的状态被更新时,触发重新渲染。如果只在组件中使用 data,SWR 将忽略其他属性(如 isValidatingisLoading)的更新。这大大减少了渲染次数。点击 这里 查看更多信息。