入门
Installation(安装)
在 React 项目目录运行以下命令:
yarn add swr
或者用 npm:
npm install swr
Quick Start(快速入门)
对于返回 JSON 数据的普通 RESTful APIs,首先需要创建一个 fetcher
函数,这个函数只是原生 fetch
的包装:
const fetcher = (...args) => fetch(...args).then(res => res.json())
如果要使用 GraphQL API 或类似 Axios 的库,可以自己创建 fetcher 函数。 点击 这里 查看更多示例。
然后你可以 import useSWR
并开始在任何函数组件中使用它:
import useSWR from 'swr'function Profile () { const { data, error } = useSWR('/api/user/123', fetcher) if (error) return <div>failed to load</div> if (!data) return <div>loading...</div> // 渲染数据 return <div>hello {data.name}!</div>}
通常,一个请求有3种可能的状态:“loading”、“ready”或“error”。你可以使用 data
和 error
的值来确定当前的请求状态,并返回相应的 UI。
Make It Reusable
在构建 web 应用时,你可能需要在 UI 的很多地方重用数据。在 SWR 上创建可重用的数据 hooks 非常容易:
function useUser (id) { const { data, error } = useSWR(`/api/user/${id}`, fetcher) return { user: data, isLoading: !error && !data, isError: error }}
在组件中使用它:
function Avatar ({ id }) { const { user, isLoading, isError } = useUser(id) if (isLoading) return <Spinner /> if (isError) return <Error /> return <img src={user.avatar} />}
通过采用这种模式,你可以不必以命令的方式请求数据:开始请求、更新加载状态并返回最终结果。 相反,你的代码更具有声明性:你只需要指定组件使用什么数据即可。
Example(示例)
在一个真实的示例中,我们的网站显示一个导航条和内容,都取决于 user
:
传统上,我们在顶级组件中使用 useEffect
请求一次数据,然后通过 props 将其传递给子组件(注意,我们现在不处理错误状态):
// 页面组件function Page () { const [user, setUser] = useState(null) // 请求数据 useEffect(() => { fetch('/api/user') .then(res => res.json()) .then(data => setUser(data)) }, []) // 全局加载状态 if (!user) return <Spinner/> return <div> <Navbar user={user} /> <Content user={user} /> </div>}// 子组件function Navbar ({ user }) { return <div> ... <Avatar user={user} /> </div>}function Content ({ user }) { return <h1>Welcome back, {user.name}</h1>}function Avatar ({ user }) { return <img src={user.avatar} alt={user.name} />}
通常,我们需要将所有的数据请求都保存在顶级组件中,并为树深处的每个组件添加 props。如果我们给页面添加更多的数据依赖,代码将变得更加难以维护。
虽然我们可以避免使用 Context 传递 props,但仍然存在动态内容问题:页面内容中的组件可以是动态的,顶级组件可能不知道其子组件将需要什么数据。
SWR 完美地解决了这个问题。使用我们刚刚创建的 useUser
hook,可以将代码重构为:
// 页面组件function Page () { return <div> <Navbar /> <Content /> </div>}// 子组件function Navbar () { return <div> ... <Avatar /> </div>}function Content () { const { user, isLoading } = useUser() if (isLoading) return <Spinner /> return <h1>Welcome back, {user.name}</h1>}function Avatar () { const { user, isLoading } = useUser() if (isLoading) return <Spinner /> return <img src={user.avatar} alt={user.name} />}
现在数据已绑定到需要该数据的组件上,并且所有组件都是相互独立的。所有的父组件都不需要关心关于数据或数据传递的任何信息。它们只是渲染。现在代码更简单,更易于维护了。
最美妙的是只有1个请求发送到 API,因为它们使用相同的 SWR key,并且请求自动重复数据删除、缓存和共享。
而且,应用现在能够在用户聚焦或网络重连时重新请求数据!这意味着当用户的笔记本电脑从睡眠状态唤醒或用户在切换浏览器标签页时,数据将自动刷新。