为什么不要在 useEffect 中进行 API 调用?

随着 React 的版本更新,内置 Hooks 越来越多了。很多 Hook 可能你压根都没听说过。但是 useEffect 这个老牌 Hook,相信每个用 React 的同学应该熟悉。

不优雅的 useEffect

不过对很多刚接触 React 的人来说,使用 useEffect 非常容易出现无限渲染循环的问题。

比如这样写:

const [count, setCount] = useState(0)

useEffect(() => {setCount(count+1)
}) 

原因是,useEffect 如果不传递第二个参数,它就会在组件每次渲染后执行。而 setCount 将会导致组件渲染。所以就会出现无限渲染循环的问题。

为了防止这个问题,我们可以给它设置第二个依赖项。依赖项是一个数组,可以传递多个引用,当其中的任意一个引用发生变化时,都会触发 effect。

const [count, setCount] = useState(0)

useEffect(() => {setCount(count+1)
}, []) 

所以我们通常都需要设置第二个依赖项来防止意想不到的事情发生。

useEffect 的设计被很多人诟病,当然也有人很喜欢它。但我认为 useEffect 在设计上确实有些草率了。

严格模式怎么办?

useEffect 可以做很多事,最常见的事情就是发起 API 调用。像下面这样:

useEffect(() => {
	fetch('/xxx')
}, []) 

React 中有严格模式,如果开启了严格模式,那么 useEffect 将会被触发两次。

这么做的好处是提醒我们,这个组件是具有副作用的。

但是对应的,我们会发起两次 API 请求。这显然是不合适的。

我知道很多人不喜欢 React 严格模式,他们会选择直接关闭它。但是如果我就是想要严格模式带来的其他好处,该怎么办?

其实也很简单,我们只需要用一个在组件每次重新渲染时不会影响的东西来记录是否被调用过就可以了。很容易就可以想到 useRef 这个东西。

所以我们可以自己实现一个在严格模式下保证 useEffect 只运行一次的 Hook。

function useEffectOnce(fn: () => void) {const canCall = useRef(false)useEffect(() => {	if(canCall.current) {fn()}return () => {canCall.current = true}}, [])
} 

这样就解决这个问题,但是它并不优雅。

性能并不好

如果在 useEffect 中发起 API 调用,那么 API 的调用将会在组件渲染完成才开始。

整个流程如下:

这个流程肯定不是最好的,因为渲染 UI 总归是要花费一些事件,尽管可能很短暂,你或许认为它无关紧要。但是性能问题往往就是积少成多导致的。

我们到底该怎么办?

对于这个问题,TanStack Query 提供了 useQuery Hook。

利用它,我们可以在组件开始渲染时同时开始 API 调用。

流程就像下面这样:

下面是一个使用 useEffect 的代码示例。

useEffect(() => {try {setLoading(true)(async () => {const data = await (await fetch('/data')).json();setData(data);})();} catch (error) {setError(error);} finally {setLoading(false);}
}, []); 

可以看到,我们除了需要处理数据以外,还要处理加载状态和异常状态。

如果使用 useQuery 会怎么样呢?

const { status, data, error, isFetching } = useQuery(['data'],async () => {const data = await (await fetch('/data')).json()return data}
) 

它会帮我们处理好加载状态、错误状态和查询结果数据的更新。

如果我们想重新运行或者终止这个 API 调用也非常简单。

只需要调用 useQuery 对应的 API 就可以了。

queryClient.invalidateQueries(['data']) 

总结

在 useEffect 中进行 API 调用很容易出错,并且性能也不好。最好的方式就是放弃这种用法,直接采用类似 useQuery 或者 SWR 这类库,可以让我们更好的进行 API 调用。

最后

最近还整理一份JavaScript与ES的笔记,一共25个重要的知识点,对每个知识点都进行了讲解和分析。能帮你快速掌握JavaScript与ES的相关知识,提升工作效率。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值