ApolloLink修改reactiveVar控制加载指示器触发渲染冲突报错如何解决
Apollo Client 全局加载状态报错修复方案
问题根因
useQuery会在调用它的业务组件渲染周期内同步执行Apollo Link链路逻辑,此时直接同步修改loadingVar会触发依赖该变量的LoadingIndicator组件同步重渲染,违反了React「不允许在组件渲染过程中更新其他组件」的规则,因此抛出报错。
修复方案
方案1:将状态更新推迟到当前渲染帧结束后执行
不需要使用React钩子,只需要用queueMicrotask把对loadingVar的修改包起来,让它在当前组件渲染逻辑执行完成后再运行即可解决冲突。同时额外增加请求计数逻辑,解决多请求并行时loading状态异常的问题:
import { ApolloLink } from '@apollo/client'; import { loadingVar } from 'gql/store/reactiveVariables'; // 全局请求计数器,处理多请求并发场景 let requestCount = 0; export const loadingLink = new ApolloLink((operation, forward) => { // 推迟更新到微任务阶段,避开当前渲染周期 queueMicrotask(() => { requestCount++; loadingVar(true); }); return forward(operation).map(data => { queueMicrotask(() => { requestCount--; if (requestCount === 0) { loadingVar(false); } }); return data; }).catch(error => { // 处理请求报错场景,避免loading状态一直为true queueMicrotask(() => { requestCount--; if (requestCount === 0) { loadingVar(false); } }); throw error; }); });
方案2:兼容低版本环境的实现
如果运行环境不支持queueMicrotask,可以用setTimeout代替,效果一致:
将上述代码中的queueMicrotask替换为setTimeout(() => {}, 0)即可。
优化建议
如果业务不需要全局统一的加载指示器,也可以直接在业务组件中使用useQuery返回的原生loading字段控制局部加载状态,完全规避全局状态更新带来的跨组件渲染冲突。
内容的提问来源于stack exchange,提问作者황연욱
相关产品推荐
相关产品推荐

