前言:
现在小伙伴们对“freeajaxmovies”大概比较重视,各位老铁们都需要知道一些“freeajaxmovies”的相关文章。那么小编在网络上汇集了一些关于“freeajaxmovies””的相关文章,希望兄弟们能喜欢,你们一起来学习一下吧!大家好,很高兴又见面了,我是"高级前端进阶",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发,您的支持是我不断创作的动力。
今天给大家带来的主题是SWR,即一个用于数据获取的 React Hooks 库。关于前端请求库的选择,以前有发表过很多文章单独介绍过,下面是已经发布的部分文章的传送门,大家感兴趣的可以选择性阅读,更多文章可以继续在我的主页查看。
《 Ajax 会被 fetch 取代吗?Axios 怎么办? 》《 为什么 JS 开发者更喜欢 Axios 而不是 Fetch? 》《 为何需要 Axios!Axios 的 5 个热门替代方案! 》《 Node 原生支持 fetch!不是浏览器那个 fetch! 》《 谁在动 Axios 的奶酪!它叫 Redaxios! 》《 霸榜掘金!轻量级请求策略库 alova 出炉!》
话不多说,直接进入正题。
1.什么是 SWR
SWR 是一个用于数据获取的 React Hooks 库,其由 Next.js(React 框架)背后的同一团队创建。SWR 的这个名字源自 stale-while-revalidate,这是一种由 HTTP RFC 5861 流行的缓存失效策略。SWR 首先从缓存返回数据(stale),然后发送请求(revalidate),如果数据变化则再次返回更新后的数据。
SWR 只需一个钩子,开发者就可以显著简化项目中的数据获取逻辑。 并且涵盖:速度、正确性、稳定性等诸多方面,帮助开发者打造更好的体验,主要包括以下几个维度:
快速、轻量级且可重用的数据获取传输和协议无关、内置缓存和请求重复数据删除实时体验、重新验证(Revalidation on focus)、网络恢复重新验证轮询、分页和滚动位置恢复支持 SSR 和 SSG、局部突变(Local mutation)(Optimistic UI)内置智能错误重试支持 TypeScript、支持 React Suspense、React Native 等等
借助 SWR,组件将不断自动获得最新数据流,UI 也会一直保持快速响应。目前 SWR 在 Github 上通过 MIT 协议开源,有超过 27.1k 的 star、1.1k 的 fork、项目依赖量 131k、代码贡献者 160+,妥妥的前端优质开源项目。
2.深入理解 SWR2.1 SWR 状态机制之请求与重新请求
useSWR 会根据 fetcher 函数的状态返回 data,error,isLoading 和 isValidating。以下这些图片描述了 SWR 在不同情况下是如何返回值的。
当用户重新聚焦一个页面或在标签页之间切换时,SWR 会自动重新请求数据。这个功能非常实用,可以保持网站同步到最新数据。
重新请求对于在长时间位于后台的标签页,或休眠等情况下刷新数据非常有用。该特性默认是启用的,开发者可以通过 revalidateOnFocus 选项禁用它。
useSWR(key, fetcher, { revalidateIfStale: false, // 控制 SWR 在挂载并且存在陈旧数据时是否应重新请求 revalidateOnFocus: false, // 聚焦时重新请求 revalidateOnReconnect: false, // 重新联机时重新请求});// 相当于useSWRImmutable(key, fetcher);2.2 Key 的变化
这种模式表示请求数据,再改变 key 值,并在之后重新请求的场景。
默认情况下,key 将作为参数传递给 fetcher。所以下面这 3 个表达式是等价的:
useSWR("/api/user", () => fetcher("/api/user"));useSWR("/api/user", (url) => fetcher(url));useSWR("/api/user", fetcher);
在某些场景中,当向 fetcher 函数传递多个参数(可以是任何值或对象)非常有用,例如授权请求。此时,开发者可以使用一个数组作为参数 key,它包含 fetcher 的多个参数:
const { data: user } = useSWR(["/api/user", token], ([url, token]) => fetchWithToken(url, token));
fetcher 函数会按原样接受 key 参数,并且缓存 key 也将与整个 key 参数数组相关联。在上面的例子中,url 和 token 都与缓存 key 相关联。
2.3 Key 的变化 + 保留之前的数据
这种模式表示在开启 keepPreviousData 选项时,请求数据,再改变 key 值,并在之后重新请求的场景。
这在用户连续操作的情况下进行数据请时对提升用户体验非常有用,例如:输入时实时搜索,保留之前的数据可以极大提升用户体验。下例是一个简单的用户搜索界面:
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 值重新开始加载,仍然可以保留之前的数据。
2.4 设置预设数据
有很多方法可以为 SWR 设置预请求数据。对于顶级请求,强烈推荐 rel="preload"
<link rel="preload" href="/api/data" as="fetch" crossorigin="anonymous">
只需把它放在 HTML 的 里即可,简单、快速、原生。它将在 HTML 加载时预请求数据,甚至是在 JavaScript 开始下载之前。使用相同 URL 的所有传入 fetch 请求都将重用结果(当然包括 SWR)。
SWR 提供预加载 API 以编程方式预取资源并将结果存储在缓存中。 preload 接受 key 和 fetcher 作为参数。 开发者甚至可以在 React 之外调用预加载。
import { useState } from "react";import useSWR, { preload } from "swr";const fetcher = (url) => fetch(url).then((res) => res.json());// 在渲染下面的 User 组件之前预加载资源,// 这可以防止应用程序中出现潜在的瀑布(waterfalls)// 也可以在悬停按钮或链接时开始预加载preload("/api/user", fetcher);function User() { const { data } = useSWR("/api/user", fetcher);}export default function App() { const [show, setShow] = useState(false); return ( <div> <button onClick={() => setShow(true)}>Show User</button> {show ? <User /> : null} </div> );}
在 React 渲染树中,预加载也可用于事件处理程序或 effect。
function App({ userId }) { const [show, setShow] = useState(false) // preload in effects useEffect(() => { preload('/api/user?id=' + userId, fetcher) }, [userId]) return ( <div> <button onClick={() => setShow(true)} {/* preload in event callbacks */} onHover={() => preload('/api/user?id=' + userId, fetcher)} > Show User </button> {show ? <User /> : null} </div> )}
配合 Next.js 的 页面预加载,开发者能立即加载下一页和数据。
import useSWR, { preload } from "swr";// 应该在渲染之前调用preload("/api/user", fetcher);preload("/api/movies", fetcher);const Page = () => { // 下面的 useSWR 钩子将暂停渲染,但是对 `/api/user` 和 `/api/movies` 的请求已经通过 `preload` 开始了, // 所以瀑布问题不会发生。 const { data: user } = useSWR("/api/user", fetcher, { suspense: true }); const { data: movies } = useSWR("/api/movies", fetcher, { suspense: true }); return ( <div> <User user={user} /> <Movies movies={movies} /> </div> );};
如果想在 SWR 缓存中预填充已经存在的数据,可以使用 fallbackData 选项,例如:
useSWR("/api/data", fetcher, { fallbackData: prefetchedData });
当 SWR 还没有获取此次数据的时候, 这个 hook 将返回 prefetchedData 作为 fallback 。
开发者也可以为所有的 SWR hooks 和不同的 key 配置 和它的 fallback 选项。
2.5 结合 isLoading 和 isValidating 以获得更好的用户体验
相比于现有的 isValidating ,isLoading 是一个新的属性,它可以帮助开发者应对更加普遍的用户加载场景。
无论数据是否已加载,只要有一个正在进行中的请求,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} </> );}3.快速使用 SWR3.1 快速开始
在 React 项目目录运行以下命令:
pnpm add swr// pnpmnpm i swr// npmyarn add swr// yarn
对于返回 JSON 数据的普通 RESTful APIs,首先需要创建一个 fetcher 函数,这个函数只是原生 fetch 的包装。当然,如果要使用 GraphQL API 或类似 Axios 的库,可以自己创建 fetcher 函数。
const fetcher = (...args) => fetch(...args).then((res) => res.json());
然后可以 import useSWR 并开始在任何函数组件中使用它:
import useSWR from "swr";function Profile() { const { data, error, isLoading } = useSWR("/api/user/123", fetcher); if (error) return <div>failed to load</div>; if (isLoading) return <div>loading...</div>; // 渲染数据 return <div>hello {data.name}!</div>;}
通常,一个请求有 3 种可能的状态:loading、ready 或 error。开发者可以使用 data、error 和 isLoading 的值来确定当前的请求状态,并返回相应的 UI。
3.2 可复用组件
在构建 web 应用时,开发者可能需要在 UI 的很多地方重用数据。在 SWR 上创建可重用的数据 hooks 非常容易:
function useUser(id) { const { data, error, isLoading } = useSWR(`/api/user/${id}`, fetcher); return { user: data, isLoading, isError: error, };}
然后可以按照下面的方式来使用它:
function Avatar({ id }) { const { user, isLoading, isError } = useUser(id); if (isLoading) return <Spinner />; if (isError) return <Error />; return <img src={user.avatar} />;}
通过采用这种模式,开发者可以不必以命令的方式请求数据:开始请求、更新加载状态并返回最终结果。 相反,代码更具有声明性,开发者只需要指定组件使用什么数据即可。
3.3 使用 SWR 优化项目
假如在一个真实的网站示例中,网站将显示一个导航条和内容,但是 UI 都取决于 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 />; // 将user传递给子组件 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,因此请求会被自动去除重、缓存和共享。
而且,应用现在能够在用户聚焦或网络重连时重新请求数据,这意味着当用户的笔记本电脑从睡眠状态唤醒,或用户在切换浏览器标签页时,数据将自动刷新。
4.本文总结
本文主要和大家介绍 SWR,即一个用于数据获取的 React Hooks 库。相信通过本文的阅读,大家对 SWR 会有一个初步的了解。
因为篇幅有限,关于 SWR 的更多用法和特性文章并没有过多展开,如果有兴趣,可以在我的主页继续阅读,同时文末的参考资料提供了大量优秀文档以供学习。最后,欢迎大家点赞、评论、转发、收藏,您的支持是我不断创作的动力。
参考资料
标签: #freeajaxmovies