@aboulman/swr 中文文档教程

发布于 5年前 浏览 25 项目主页 更新于 3年前

SWR< /a>

Introduction

swr.now.sh

SWR 是一个用于远程数据获取的 React Hooks 库。

SWR”这个名称源自 stale-while-revalidate,这是一种由 HTTP RFC 5861
SWR 首先从缓存中返回数据(stale),然后发送获取请求(revalidate),最后再次带来最新的数据。

它的特点是:

  • Transport and protocol agnostic data fetching
  • Fast page navigation
  • Revalidation on focus
  • Interval polling
  • Local mutation
  • Pagination
  • TypeScript ready
  • SSR support
  • Suspense mode
  • React Native support
  • Minimal API

……还有更多。

借助 SWR,组件将不断自动更新数据流。 因此,UI 将始终快速响应式


Quick Start

import useSWR from 'swr'

function Profile () {
  const { data, error } = useSWR('/api/user', fetcher)

  if (error) return <div>failed to load</div>
  if (!data) return <div>loading...</div>
  return <div>hello {data.name}!</div>
}

在此示例中,React Hook useSWR 接受一个 key 和一个 fetcher 函数。 key 是请求的唯一标识符,通常是 API 的 URL。 fetcher 接受 key 作为其参数并异步返回数据。

useSWR 还返回 2 个值:dataerror。 当请求(fetcher)还没有完成时, data 将是 undefined。 当我们得到响应时,它会根据结果设置 dataerror fetcher 并重新渲染组件。

请注意,fetcher 可以是任何异步函数,因此您可以使用自己喜欢的数据获取 库来处理那部分。

查看 swr.now.sh 了解更多 SWR 演示,以及示例最佳实践。


Usage

在您的 React 项目目录中,运行以下命令:

yarn add swr

或使用 npm:

npm install swr

API

const { data, error, isValidating, revalidate } = useSWR(key, fetcher, options)

Parameters

  • key: a unique key string for the request (or a function / array / null) (advanced usage)
  • fetcher: (optional) a Promise returning function to fetch your data (details)
  • options: (optional) an object of options for this SWR hook

Return Values

  • data: data for the given key resolved by fetcher (or undefined if not loaded)
  • error: error thrown by fetcher (or undefined)
  • isValidating: if there's a request or revalidation loading
  • revalidate: function to trigger the validation manually

Options

  • suspense = false: enable React Suspense mode (details)
  • fetcher = undefined: the default fetcher function
  • initialData: initial data to be returned (note: This is per-hook)
  • revalidateOnFocus = true: auto revalidate when window gets focused
  • refreshInterval = 0: polling interval (disabled by default)
  • refreshWhenHidden = false: polling when the window is invisible (if refreshInterval is enabled)
  • shouldRetryOnError = true: retry when fetcher has an error (details)
  • dedupingInterval = 2000: dedupe requests with the same key in this time span
  • focusThrottleInterval = 5000: only revalidate once during a time span
  • loadingTimeout = 3000: timeout to trigger the onLoadingSlow event
  • errorRetryInterval = 5000: error retry interval (details)
  • onLoadingSlow: callback function when a request takes too long to load (see loadingTimeout)
  • onSuccess: callback function when a request finishes successfully
  • onError: callback function when a request returns an error
  • onErrorRetry: handler for error retry

在慢速网络(2G,<= 70Kbps)下,errorRetryInterval 将为 10 秒,并且 loadingTimeout 默认为 5s。

您还可以使用全局配置 来提供默认选项。


Examples

Global Configuration

上下文SWRConfig 可以为所有SWR 挂钩提供全局配置(选项)。

在此示例中,所有 SWR 将使用提供的相同提取器来加载 JSON 数据,默认情况下每 3 秒刷新一次:

import useSWR, { SWRConfig } from 'swr'

function Dashboard () {
  const { data: events } = useSWR('/api/events')
  const { data: projects } = useSWR('/api/projects')
  const { data: user } = useSWR('/api/user', { refreshInterval: 0 }) // don't refresh
  // ...
}

function App () {
  return (
    <SWRConfig 
      value={{
        refreshInterval: 3000,
        fetcher: (...args) => fetch(...args).then(res => res.json())
      }}
    >
      <Dashboard />
    </SWRConfig>
  )
}

Data Fetching

fetcher 是一个接受key 的函数 的 SWR,并返回一个值或一个 Promise。
您可以使用任何库来处理数据获取,例如:

import fetch from 'unfetch'

const fetcher = url => fetch(url).then(r => r.json())

function App () {
  const { data } = useSWR('/api/data', fetcher)
  // ...
}

或使用 GraphQL:

import { request } from 'graphql-request'

const API = 'https://api.graph.cool/simple/v1/movies'
const fetcher = query => request(API, query)

function App () {
  const { data, error } = useSWR(
    `{
      Movie(title: "Inception") {
        releaseDate
        actors {
          name
        }
      }
    }`,
    fetcher
  )
  // ...
}

如果您想将变量传递给 GraphQL 查询,请查看Multiple Arguments .

请注意,如果全局提供 fetcher,则可以从参数中省略它。

Conditional Fetching

使用 null 或将函数作为 key 传递给 useSWR 以有条件地获取数据。 如果函数抛出错误或返回错误值,SWR 将取消请求。

// conditionally fetch
const { data } = useSWR(shouldFetch ? '/api/data' : null, fetcher)

// ...or return a falsy value
const { data } = useSWR(() => shouldFetch ? '/api/data' : null, fetcher)

// ... or throw an error when user.id is not defined
const { data } = useSWR(() => '/api/data?uid=' + user.id, fetcher)

Dependent Fetching

SWR 还允许您获取依赖于其他数据的数据。 它确保最大可能的并行性(避免瀑布),以及在下一次数据获取需要一段动态数据时进行串行获取。

function MyProjects () {
  const { data: user } = useSWR('/api/user')
  const { data: projects } = useSWR(() => '/api/projects?uid=' + user.id)
  // When passing a function, SWR will use the
  // return value as `key`. If the function throws,
  // SWR will know that some dependencies are not
  // ready. In this case it is `user`.

  if (!projects) return 'loading...'
  return 'You have ' + projects.length + ' projects'
}

Multiple Arguments

在某些情况下,将多个参数(可以是任何值或对象)传递给 fetcher 函数很有用。 例如:

useSWR('/api/user', url => fetchWithToken(url, token))

这是不正确。 因为数据的标识(也是缓存的索引)是'/api/data', 因此,即使 token 发生变化,SWR 仍将具有相同的密钥并返回错误的数据。

相反,您可以使用一个array 作为key 参数,它包含fetcher 的多个参数:

const { data: user } = useSWR(['/api/user', token], fetchWithToken)

// ...and pass it as an argument to another query
const { data: orders } = useSWR(user ? ['/api/orders', user] : null, fetchWithUser)

请求的键现在是组合两个值。 SWR 比较 每个渲染器的参数,如果其中任何一个发生变化则触发重新验证。
请记住,渲染时不应重新创建对象,因为它们在每次渲染时都会被视为不同的对象:

// Don’t do this! Deps will be changed on every render.
useSWR(['/api/user', { id }], query)

// Instead, you should only pass “stable” values.
useSWR(['/api/user', id], (url, id) => query(url, { id }))

Dan Abramov 在 这篇博文

Manually Revalidate

您可以通过调用 <代码>触发器(键)

此示例显示如何自动重新获取登录信息(例如:在 中) 当用户单击“注销”按钮时。

import useSWR, { trigger } from 'swr'

function App () {
  return (
    <div>
      <Profile />
      <button onClick={() => {
        // set the cookie as expired
        document.cookie = 'token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;'

        // tell all SWRs with this key to revalidate
        trigger('/api/user')
      }}>
        Logout
      </button>
    </div>
  )
}

Mutation and Post Request

在许多情况下,对数据应用局部突变是进行更改的好方法 感觉更快——无需等待远程数据源。

使用 mutate,您可以以编程方式更新本地数据,同时 重新验证并最终用最新数据替换它。

import useSWR, { mutate } from 'swr'

function Profile () {
  const { data } = useSWR('/api/user', fetcher)

  return (
    <div>
      <h1>My name is {data.name}.</h1>
      <button onClick={async () => {
        const newName = data.name.toUpperCase()
        // send a request to the API to update the data
        await requestUpdateUsername(newName)
        // update the local data immediately and revalidate (refetch)
        mutate('/api/user', { ...data, name: newName })
      }}>Uppercase my name!</button>
    </div>
  )
}

点击上例中的按钮,会发送POST请求修改远程数据,本地更新客户端数据, 尝试获取最新的(重新验证)。

但是很多POST API会直接返回更新后的数据,所以我们不需要重新验证。
下面是一个显示“local mutate - request - update”用法的示例:

mutate('/api/user', newUser, false)      // use `false` to mutate without revalidation
mutate('/api/user', updateUser(newUser)) // `updateUser` is a Promise of the request,
                                         // which returns the updated document

SSR with Next.js

使用 initialData 选项,您可以将初始值传递给挂钩。 它与许多 SSR 解决方案完美配合 比如Next.js中的getInitialProps

App.getInitialProps = async () => {
  const data = await fetcher('/api/data')
  return { data }
}

function App (props) {
  const initialData = props.data
  const { data } = useSWR('/api/data', fetcher, { initialData })

  return <div>{data}</div>
}

它仍然是服务端渲染的站点,但是它还完全由客户端的 SWR 提供支持。 这意味着数据可以是动态的,并随着时间和用户交互而自我更新。

Suspense Mode

您可以启用 suspense 选项以将 SWR 与 React Suspense 一起使用:

import { Suspense } from 'react'
import useSWR from 'swr'

function Profile () {
  const { data } = useSWR('/api/user', fetcher, { suspense: true })
  return <div>hello, {data.name}</div>
}

function App () {
  return (
    <Suspense fallback={<div>loading...</div>}>
      <Profile/>
    </Suspense>
  )
}

在 Suspense 模式下,data 始终是获​​取响应(因此您无需检查它是否是 未定义)。 但是,如果发生错误,您需要使用 错误边界 来捕获它。

请注意,SSR 模式不支持 Suspense。

Error Retries

默认情况下,SWR 使用指数退避算法处理错误重试。 您可以从源代码中阅读更多内容。

也可以覆盖该行为:

useSWR(key, fetcher, {
  onErrorRetry: (error, key, option, revalidate, { retryCount }) => {
    if (retryCount >= 10) return
    if (error.status === 404) return

    // retry after 5 seconds
    setTimeout(() => revalidate({ retryCount: retryCount + 1 }), 5000)
  }
})

Prefetching Data

有许多方法可以为 SWR 预取数据。 对于顶级请求,rel="preload" 是强烈推荐:

<link rel="preload" href="/api/data" as="fetch" crossorigin="anonymous">

这将在 JavaScript 开始下载之前预取数据。 并且您传入的获取请求将重用结果(当然包括 SWR)。

另一种选择是有条件地预取数据。 你可以有一个函数来重新获取和设置缓存:

function prefetch () {
  mutate('/api/data', fetch('/api/data').then(res => res.json()))
  // the second parameter is a Promise
  // SWR will use the result when it resolves
}

并在你需要预加载资源时使用它(例如当 悬停 a 链接 ).
结合 Next.js 中的页面预取等技术,您将能够立即加载下一页和数据。


Authors

感谢 Ryan Chen 提供了很棒的 swr npm 包名!


License

麻省理工学院许可证。

SWR

Introduction

swr.now.sh

SWR is a React Hooks library for remote data fetching.

The name “SWR” is derived from stale-while-revalidate, a cache invalidation strategy popularized by HTTP RFC 5861.
SWR first returns the data from cache (stale), then sends the fetch request (revalidate), and finally comes with the up-to-date data again.

It features:

  • Transport and protocol agnostic data fetching
  • Fast page navigation
  • Revalidation on focus
  • Interval polling
  • Local mutation
  • Pagination
  • TypeScript ready
  • SSR support
  • Suspense mode
  • React Native support
  • Minimal API

…and a lot more.

With SWR, components will get a stream of data updates constantly and automatically. Thus, the UI will be always fast and reactive.


Quick Start

import useSWR from 'swr'

function Profile () {
  const { data, error } = useSWR('/api/user', fetcher)

  if (error) return <div>failed to load</div>
  if (!data) return <div>loading...</div>
  return <div>hello {data.name}!</div>
}

In this example, the React Hook useSWR accepts a key and a fetcher function. key is a unique identifier of the request, normally the URL of the API. And the fetcher accepts key as its parameter and returns the data asynchronously.

useSWR also returns 2 values: data and error. When the request (fetcher) is not yet finished, data will be undefined. And when we get a response, it sets data and error based on the result of fetcher and rerenders the component.

Note that fetcher can be any asynchronous function, so you can use your favourite data-fetching library to handle that part.

Check out swr.now.sh for more demos of SWR, and Examples for the best practices.


Usage

Inside your React project directory, run the following:

yarn add swr

Or with npm:

npm install swr

API

const { data, error, isValidating, revalidate } = useSWR(key, fetcher, options)

Parameters

  • key: a unique key string for the request (or a function / array / null) (advanced usage)
  • fetcher: (optional) a Promise returning function to fetch your data (details)
  • options: (optional) an object of options for this SWR hook

Return Values

  • data: data for the given key resolved by fetcher (or undefined if not loaded)
  • error: error thrown by fetcher (or undefined)
  • isValidating: if there's a request or revalidation loading
  • revalidate: function to trigger the validation manually

Options

  • suspense = false: enable React Suspense mode (details)
  • fetcher = undefined: the default fetcher function
  • initialData: initial data to be returned (note: This is per-hook)
  • revalidateOnFocus = true: auto revalidate when window gets focused
  • refreshInterval = 0: polling interval (disabled by default)
  • refreshWhenHidden = false: polling when the window is invisible (if refreshInterval is enabled)
  • shouldRetryOnError = true: retry when fetcher has an error (details)
  • dedupingInterval = 2000: dedupe requests with the same key in this time span
  • focusThrottleInterval = 5000: only revalidate once during a time span
  • loadingTimeout = 3000: timeout to trigger the onLoadingSlow event
  • errorRetryInterval = 5000: error retry interval (details)
  • onLoadingSlow: callback function when a request takes too long to load (see loadingTimeout)
  • onSuccess: callback function when a request finishes successfully
  • onError: callback function when a request returns an error
  • onErrorRetry: handler for error retry

When under a slow network (2G, <= 70Kbps), errorRetryInterval will be 10s, and loadingTimeout will be 5s by default.

You can also use global configuration to provide default options.


Examples

Global Configuration

The context SWRConfig can provide global configurations (options) for all SWR hooks.

In this example, all SWRs will use the same fetcher provided to load JSON data, and refresh every 3 seconds by default:

import useSWR, { SWRConfig } from 'swr'

function Dashboard () {
  const { data: events } = useSWR('/api/events')
  const { data: projects } = useSWR('/api/projects')
  const { data: user } = useSWR('/api/user', { refreshInterval: 0 }) // don't refresh
  // ...
}

function App () {
  return (
    <SWRConfig 
      value={{
        refreshInterval: 3000,
        fetcher: (...args) => fetch(...args).then(res => res.json())
      }}
    >
      <Dashboard />
    </SWRConfig>
  )
}

Data Fetching

fetcher is a function that accepts the key of SWR, and returns a value or a Promise.
You can use any library to handle data fetching, for example:

import fetch from 'unfetch'

const fetcher = url => fetch(url).then(r => r.json())

function App () {
  const { data } = useSWR('/api/data', fetcher)
  // ...
}

Or using GraphQL:

import { request } from 'graphql-request'

const API = 'https://api.graph.cool/simple/v1/movies'
const fetcher = query => request(API, query)

function App () {
  const { data, error } = useSWR(
    `{
      Movie(title: "Inception") {
        releaseDate
        actors {
          name
        }
      }
    }`,
    fetcher
  )
  // ...
}

If you want to pass variables to a GraphQL query, check out Multiple Arguments.

Note that fetcher can be omitted from the parameters if it's provided globally.

Conditional Fetching

Use null or pass a function as the key to useSWR to conditionally fetch data. If the functions throws an error or returns a falsy value, SWR will cancel the request.

// conditionally fetch
const { data } = useSWR(shouldFetch ? '/api/data' : null, fetcher)

// ...or return a falsy value
const { data } = useSWR(() => shouldFetch ? '/api/data' : null, fetcher)

// ... or throw an error when user.id is not defined
const { data } = useSWR(() => '/api/data?uid=' + user.id, fetcher)

Dependent Fetching

SWR also allows you to fetch data that depends on other data. It ensures the maximum possible parallelism (avoiding waterfalls), as well as serial fetching when a piece of dynamic data is required for the next data fetch to happen.

function MyProjects () {
  const { data: user } = useSWR('/api/user')
  const { data: projects } = useSWR(() => '/api/projects?uid=' + user.id)
  // When passing a function, SWR will use the
  // return value as `key`. If the function throws,
  // SWR will know that some dependencies are not
  // ready. In this case it is `user`.

  if (!projects) return 'loading...'
  return 'You have ' + projects.length + ' projects'
}

Multiple Arguments

In some scenarios, it's useful pass multiple arguments (can be any value or object) to the fetcher function. For example:

useSWR('/api/user', url => fetchWithToken(url, token))

This is incorrect. Because the identifier (also the index of the cache) of the data is '/api/data', so even if token changes, SWR will still have the same key and return the wrong data.

Instead, you can use an array as the key parameter, which contains multiple arguments of fetcher:

const { data: user } = useSWR(['/api/user', token], fetchWithToken)

// ...and pass it as an argument to another query
const { data: orders } = useSWR(user ? ['/api/orders', user] : null, fetchWithUser)

The key of the request is now the combination of both values. SWR shallowly compares the arguments on every render, and triggers revalidation if any of them has changed.
Keep in mind that you should not recreate objects when rendering, as they will be treated as different objects on every render:

// Don’t do this! Deps will be changed on every render.
useSWR(['/api/user', { id }], query)

// Instead, you should only pass “stable” values.
useSWR(['/api/user', id], (url, id) => query(url, { id }))

Dan Abramov explains dependencies very well in this blog post.

Manually Revalidate

You can broadcast a revalidation message globally to all SWRs with the same key by calling trigger(key).

This example shows how to automatically refetch the login info (e.g.: inside <Profile/>) when the user clicks the “Logout” button.

import useSWR, { trigger } from 'swr'

function App () {
  return (
    <div>
      <Profile />
      <button onClick={() => {
        // set the cookie as expired
        document.cookie = 'token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;'

        // tell all SWRs with this key to revalidate
        trigger('/api/user')
      }}>
        Logout
      </button>
    </div>
  )
}

Mutation and Post Request

In many cases, applying local mutations to data is a good way to make changes feel faster — no need to wait for the remote source of data.

With mutate, you can update your local data programmatically, while revalidating and finally replace it with the latest data.

import useSWR, { mutate } from 'swr'

function Profile () {
  const { data } = useSWR('/api/user', fetcher)

  return (
    <div>
      <h1>My name is {data.name}.</h1>
      <button onClick={async () => {
        const newName = data.name.toUpperCase()
        // send a request to the API to update the data
        await requestUpdateUsername(newName)
        // update the local data immediately and revalidate (refetch)
        mutate('/api/user', { ...data, name: newName })
      }}>Uppercase my name!</button>
    </div>
  )
}

Clicking the button in the example above will send a POST request to modify the remote data, locally update the client data and try to fetch the latest one (revalidate).

But many POST APIs will just return the updated data directly, so we don’t need to revalidate again.
Here’s an example showing the “local mutate - request - update” usage:

mutate('/api/user', newUser, false)      // use `false` to mutate without revalidation
mutate('/api/user', updateUser(newUser)) // `updateUser` is a Promise of the request,
                                         // which returns the updated document

SSR with Next.js

With the initialData option, you pass an initial value to the hook. It works perfectly with many SSR solutions such as getInitialProps in Next.js:

App.getInitialProps = async () => {
  const data = await fetcher('/api/data')
  return { data }
}

function App (props) {
  const initialData = props.data
  const { data } = useSWR('/api/data', fetcher, { initialData })

  return <div>{data}</div>
}

It is still a server-side rendered site, but it’s also fully powered by SWR in the client side. Which means the data can be dynamic and update itself over time and user interactions.

Suspense Mode

You can enable the suspense option to use SWR with React Suspense:

import { Suspense } from 'react'
import useSWR from 'swr'

function Profile () {
  const { data } = useSWR('/api/user', fetcher, { suspense: true })
  return <div>hello, {data.name}</div>
}

function App () {
  return (
    <Suspense fallback={<div>loading...</div>}>
      <Profile/>
    </Suspense>
  )
}

In Suspense mode, data is always the fetch response (so you don't need to check if it's undefined). But if an error occurred, you need to use an error boundary to catch it.

Note that Suspense is not supported in SSR mode.

Error Retries

By default, SWR uses the exponential backoff algorithm to handle error retries. You can read more from the source code.

It's also possible to override the behavior:

useSWR(key, fetcher, {
  onErrorRetry: (error, key, option, revalidate, { retryCount }) => {
    if (retryCount >= 10) return
    if (error.status === 404) return

    // retry after 5 seconds
    setTimeout(() => revalidate({ retryCount: retryCount + 1 }), 5000)
  }
})

Prefetching Data

There’re many ways to prefetch the data for SWR. For top level requests, rel="preload" is highly recommended:

<link rel="preload" href="/api/data" as="fetch" crossorigin="anonymous">

This will prefetch the data before the JavaScript starts downloading. And your incoming fetch requests will reuse the result (including SWR, of course).

Another choice is to prefetch the data conditionally. You can have a function to refetch and set the cache:

function prefetch () {
  mutate('/api/data', fetch('/api/data').then(res => res.json()))
  // the second parameter is a Promise
  // SWR will use the result when it resolves
}

And use it when you need to preload the resources (for example when hovering a link).
Together with techniques like page prefetching in Next.js, you will be able to load both next page and data instantly.


Authors

Thanks to Ryan Chen for providing the awesome swr npm package name!


License

The MIT License.

更多

友情链接

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文