React+Apollo中ProgressBar调用refetch如何避免MemoBox同步更新
问题根因
Apollo Client默认会全局共享相同查询+相同变量的缓存结果,任意一处触发该查询的refetch更新缓存后,所有订阅该查询的组件都会收到更新通知,所以MemoBox会跟随ProgressBar的刷新动作重渲染。
可选解决方案
方案1:MemoBox手动拉取一次数据,不订阅缓存更新
直接用Apollo Client实例手动查询一次数据,存在本地state,后续缓存更新不会触发组件重渲染,适合MemoBox完全不需要后续更新用户数据的场景:
import { useApolloClient } from '@apollo/client'; import { useState, useEffect } from 'react'; const MemoBox = () => { const {userId} = useParams<{userId: string}>(); const client = useApolloClient(); const [memoHtml, setMemoHtml] = useState(''); useEffect(() => { if (!userId) return; client.query({ query: USER_QUERY, // 替换为你实际的USER_QUERY定义 variables: { uuid: userId } }).then(res => { if (res.data?.user?.memoHtml) { setMemoHtml(res.data.user.memoHtml); } }) }, [userId, client]); if (!memoHtml) return null; return ( <Memo dangerouslySetInnerHTML={{__html: memoHtml}} /> ) }
方案2:给MemoBox的查询加select过滤,仅当依赖字段变化时重渲染
利用Apollo useQuery的select配置,仅提取MemoBox依赖的memoHtml字段,只要该字段值不变,就不会触发组件重渲染,适合后续可能需要更新memo内容的场景:
const MemoBox = () => { const {userId} = useParams<{userId: string}>(); // 直接提取memoHtml,值不变时不会触发重渲染 const { data: memoHtml } = useUserQuery({ variables: { uuid: userId }, skip: !userId, select: (data) => data.user?.memoHtml }); if (!memoHtml) return null; return ( <Memo dangerouslySetInnerHTML={{__html: memoHtml}} /> ) }
方案3:ProgressBar的刷新不更新全局缓存
给ProgressBar的refetch指定no-cache策略,刷新结果不写入全局缓存,自然不会触发其他订阅该查询的组件更新:
import { useState } from 'react'; import {useInterval} from 'beautiful-react-hooks'; const ProgressBar = () => { const {userId} = useParams<{userId: string}>(); const [percent, setPercent] = useState(0); const { refetch: refetchUser } = useUserQuery({ variables: {uuid: userId}, skip: !userId, }); useInterval(() => { // 刷新结果不进全局缓存 refetchUser({ fetchPolicy: 'no-cache' }).then(res => { if (res.data?.user?.percent) { setPercent(res.data.user.percent); } }) }, 3000); return ( <p>{percent}</p> ) }
选型建议
- 若MemoBox不需要任何后续更新,优先选方案1
- 若MemoBox的memo内容可能会被其他操作更新,优先选方案2
- 若你不想修改MemoBox的逻辑,优先选方案3
内容的提问来源于stack exchange,提问作者user15375616
相关产品推荐
相关产品推荐

