携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第2天,点击查看活动详情
这是我关于 ahooks - useRequest 系列文章的第二篇,其他两篇请查看:
在上一篇文章:使用 ahooks 中的 useRequest 轻松管理React中的网络请求 ,我们介绍了 useRequest
这个 Hook 的使用以及配置。
本文我们主要介绍如何通过 useRequest
实现乐观更新。
什么是乐观更新
乐观更新 Optimistic Updates,即不等待接口返回数据,在发起请求时就对数据进行修改,提前将交互结果显示在用户界面上。
一般的应用乐观更新的场景,是对数据源的可预测修改,即请求发出后我们可以知道成功 或者 失败 会对源数据产生什么影响。
举个栗子,假如我们要对用户信息进行修改一般涉及到如下两个接口:
[get] api/user/id
获取到用户信息[put] api/user/id
修改用户信息
一般来说,接口2
在提交成功后只会返回成功或者失败的信息,那么我们通常是在接口2
调用成功后,再次请求接口1
更新页面。
就像我前面说的这个概念这是一个非常典型的可预测修改,我们其实完全没有必要再次请求接口1,完全可以使用我们自己已有的数据来修改原来的数据源,从而减少网络请求次数、提高用户界面响应速度。
普通:接口1
-> 接口2
-> 接口1
,一发送3个请求需要等待时间较长,用户界面响应取决于网络响应
乐观更新:接口1
-> 接口2
(本地修改数据源),只发送两次请求,只等待一次接口1
的响应
简单来说乐观更新的概念,就是我们乐观的认为这个修改请求会成功,并且我们可以预测成功或失败后数据源如何变化,在真实数据(服务端状态)变化之前,修改用户本地数据刷新用户界面。
如何实现
这里就要请出我们在上一篇文章介绍的 mutate
函数与生命周期回调,用我们上面修改用户信息的例子写一个简单的demo,我会分步骤来介绍每一个步骤的意义。
-
接口模拟
// 模拟请求用户信息 const fetchUserInfo = (id) => { return new Promise((resolve, reject) => { setTimeout(() => { resolve({ name: `John`, id, time: new Date().toLocaleString() }); }, 500); }) } // 模拟修改用户信息接口请求成功 or 失败 const changeUserName = (name) => { return new Promise((resolve, reject) => { setTimeout(() => { if (Math.random() > 0.5) { resolve(); } else { reject(new Error('Failed to modify username')); } }, 1000); }); }
-
在组件中使用 useRequest
// 接口1 获取用户信息接口 const { data, loading, error, run, refresh, mutate } = useRequest(() => fetchUserInfo(id)); // 使用 usePrevious 保存上一次的数据 const originData = usePrevious(data); // 接口2 修改用户接口 const { run: updateName } = useRequest(changeUserName, { manual: true, onError: () => { // 乐观更新失败使用原始数据恢复 mutate(originData); alert('操作失败!'); } })
这里我们额外引入了 ahooks 中的一个 钩子函数:usePrevious,它可以帮我们保存状态变更前的值,这样我们可以方便的通过它来回溯数据,这个钩子函数我们以后有机会会专门介绍一下。
这里要注意,
mutate
函数是来自于数据源接口,用来操作数据源状态。用于引起突变的实际是接口2,我们将它设置为手动触发,并且配置生命周期函数。当请求成功时说明对服务端状态修改成功,一般来说不需要额外操作。失败时,说明乐观更新失败,我们需要用原始数据来恢复用户界面并对用户进行提示。 -
处理突变
const handleChange = () => { if (name) { // 发起修改请求 updateName(name); // 发起请求时通过mutate函数乐观更新原始数据 mutate(state => ({ ...state, name })) } }
处理突变这里很好理解,就是引起突变的请求发出后,我们就应该立即使用
mutate
函数,改变原始数据,进行乐观更新。
题外话
在 ahooks 中实现乐观更新的操作步骤上虽然有一点繁琐,但是胜在逻辑很容易理解。比较起 react-query 来说,useRequest
需要多些一些代码,例如需要自己保存修改之前的原始数据(用于突变失败后的数据恢复)。
一般来说我们在大多数情况都不是必须使用乐观更新,他不是一个必选项,只有在频繁涉及到这种可预测修改时,可以使用乐观更新来优化用户体验。
乐观更新的限定一定是可预测修改,如果一个操作之后对用户界面的影响是未知的,那么我们只能按照原来的方式处理。
个人感官上,useRequest 可以作为接触 服务端状态管理 的入门,如果我们要深入的学习理解 服务端状态管理 ,还是需要去学习 诸如 react-query 或者 rtk-query 的。
上文演示的乐观更新其实并不适合应用于生产,这更多是一个入门的demo,我会在下一篇文章介绍 swr、数据缓存、数据共享时,改造这段代码,让他更符合真实应用时的使用方法,敬请期待!