实现自己的 API Client
在项目内实现异步请求时第一个事情就是创建自己的 API Client,之后所有的请求都可以通过这个 Client 发出去。
- 一些通用的 header
- 服务器地址的配置:比如可以根据当前环境判断连接的服务器地址
- 请求未认证的处理
使用 Hooks 思考异步请求:封装远程资源
对于一个 get 类型的 API,可以将它看成一个远程的数据源:
- Data
- Error
- Pending
比起将请求直接写在组件内部,迁移到一个 Hook 内可以把组件的表现层逻辑写得更加简洁,将 API 的调用看作一个数据获取。
之后只需要将获取到的数据映射到 JSX 并显示出来即可。
这个模式仅适用于 get 请求逻辑,对于其他类型可查看第六节的 useAsync。
多个 API 调用:处理并发或者串行请求
比如一个博客文章展示页面的场景,这里需要三个请求:
- 文章详情
- 作者信息,包括名字,头像等
- 文章的评论
此时包含了并发和串行的场景,文章详情和评论可以并发请求,作者的信息需要等文章内容返回才能知道作者 ID,这是串行场景。
// 传统场景
const [article, comments] = await Promise.all([
fetchArticle(id)
fetchComments(id)
])
const user = await fetchUser(article.user_id)
React 函数组件是一个同步函数,没有办法直接使用 await 这样的同步方法,而是需要将请求通过副作用去触发。
此时需要回到 React 的本质——状态驱动 UI。
可以从状态变化的角度去组织异步调用,通过不同的状态组合来实现异步请求的逻辑。
此时的实现思路:
- 组件首次渲染,需要两个副作用去获取文章和评论
- 组件首次渲染,作者 ID 不存在不发送任何请求
- 文章内容返回,开始发送请求作者信息
- 展示作者信息
const { data: article, loading, error } = useArticle(id);
const { data: comments } = useComments(id);
const { data: user } = useUser(article?.user_id);
// 在useUser内增加一个user_id的依赖项和判断
思考
每次调用 useArticle 这个 Hook 就会触发副作用去获取数据,但是有时候需要组件自动获取,有些需要点击某个按钮才去获取,此时如何去设计这个 Hook?
我的回答:增加一个是否请求的 deps?
Hook 都是使用 useState 保存了状态数据,意味着状态的范围限定在组件内部,组件销毁后数据就没了,此时希望数据直接缓存到全部状态该如何做?
我的回答:使用 redux 或者 localStorage?