为何useQuery结合useEffect不会引发组件无限重渲染?
为什么这段React+Apollo代码不会无限重渲染?
我有如下代码片段:
const [state, setState] = useState(null); const {data, loading, error} = useQuery(SOME_QUERY, {fetchPolicy: 'no-cache'}); useEffect(() => { setState(data) }, [data]);
这段代码似乎仅渲染两次:一次是首次渲染,另一次是GraphQL请求完成后。我的疑问是:为何这不会导致组件无限重渲染?
我原本以为的流程是:组件渲染→useQuery发起请求→请求完成→useEffect更新state→触发再次渲染→useQuery再次发起请求,如此循环。
另外我也只看到一次网络请求,是否是useQuery在内部管理了这一切?
原因解析
useQuery不会重复发起无变化的请求:useQuery内部自带请求管理逻辑,同一个查询(查询语句、参数都不变)只会发起一次网络请求。哪怕组件重新渲染,只要查询的核心内容没改,它就不会再次触发请求——你设置的
no-cache只是不把结果存入Apollo的全局缓存,但不影响它内部的重复请求拦截机制,所以你只会看到一次网络请求。useEffect的依赖项稳定后不会重复执行:组件首次渲染时,
data为undefined或null(处于loading状态);当请求完成,data更新为接口返回的实际数据,此时useEffect的依赖项data发生变化,触发setState(data),导致组件再次渲染。但这次重新渲染时,data已经是最终的稳定值,和上一次的data完全一致,useEffect的依赖项没有变化,所以不会再次执行,自然不会调用setState触发下一轮渲染,循环也就终止了。完整流程梳理:
- 组件首次渲染,useQuery发起请求,此时loading为true,data为空,useEffect因依赖项无变化不执行
- 请求完成,data更新,触发组件重新渲染,useEffect检测到data变化,执行setState更新组件state
- 组件因state更新再次渲染,此时useQuery返回的data已是最终值,和依赖项里的data完全相同,useEffect不执行,不再触发新的渲染或请求
内容的提问来源于stack exchange,提问作者Mrityu
相关产品推荐
相关产品推荐

