如何在不重新验证的情况下从useSWR中推导出“加载”?

16

有人问了我一个关于 SWR 的“加载”状态的问题:

如何在不同的 URL 获取之间从 SWR 创建加载状态?

他们的文档 让它看起来很简单:

  const { data, error } = useSWR(`/api/user/${id}`, fetcher)
  const isLoading = !error && !data;

然而,这个逻辑在钩子/组件的第一次渲染后似乎失败了。在第一次渲染时,数据为undefined。然后加载数据并成为UI中要消耗的值。
假设我通过UI更改了id并想显示加载指示器。由于data不再是undefined,同样的逻辑失败了。
还有一个额外的返回项isValidating。所以我更新了我的逻辑:
const isLoading = (!data && !error) || isValidating

然而,仅当以下情况之一成立时才可能是正确的:

存在请求或重新验证加载。

因此,从理论上讲,其他事物会导致我的组件重新呈现。这可能会意外地导致“重新验证”,并触发显示加载状态。 这可能会意外破坏UI。

那么,在不重新验证的情况下如何在URL更改之间推断“loading”? 我正在尝试复制GraphQL Apollo Client返回的方式:const { loading, error, data } = useQuery(GET_DOGS);

2个回答

16
假设我通过 UI 修改了 id 并想要显示加载指示器。由于 data 不再是 undefined,相同的逻辑会失败。
如果关键字(id)没有缓存值,则在更改关键字时 data 将再次变为 undefined
请记住,在 SWR 中 { data } = useSWR(key) 等效于 v = getCache(k),其中 fetcher(验证器)只写入缓存并触发重新渲染。
data 默认为 undefined,而 isValidating 表示是否有正在进行的请求。

5

或者,您可以通过使用中间件来派生加载。这是我使用的内容...

loadingMiddleware.ts

import { useState } from 'react'
import { Middleware } from 'swr'

const loadingMiddleware: Middleware = (useSWRNext) => (key, fetcher, config) => {
  const [loading, setLoading] = useState(false)

  const extendedFetcher = (...args) => {
    setLoading(true)
    try {
      return fetcher(...args)
    } finally {
      setLoading(false)
    }
  }

  const swr = useSWRNext(key, extendedFetcher, config)

  return { ...swr, loading }
}

export default loadingMiddleware

App.tsx

import { SWRConfig } from 'swr'
import loadingMiddleware from './loadingMiddleware'

const App: FC = () => {
  ...

  return (
    <SWRConfig value={{ use: [loadingMiddleware] }}>
      ...
    </SWRConfig>
  )
}

export default App

更新(12/13/22)

swr@v2已发布并在useSWR的返回值中提供了isLoadingisValidating属性。

根据swr文档,它们之间的区别如下:

  • 只要有正在进行的请求,无论数据是否已加载,isValidating就会变为true。
  • 只有在有正在进行的请求且数据尚未加载时,isLoading才会变为true。

“loaded”这个词的意思是数据有一个缓存版本吗? - OGreeni
1
是的。换句话说,useSWR 返回的 data 属性已经被填充了。他们还指出:“备用数据和先前的数据不被视为“已加载的数据”,因此当您使用备用数据或启用 keepPreviousData 选项时,您可能会有数据可供显示。” - bflemi3

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接