useState更新引发useQuery两次调用的技术问题咨询
解决useQuery重复调用的问题
问题根源是组件初始化时filterState的初始值为false,触发第一次查询;随后useEffect从本地存储获取到真实值并更新filterState,导致组件重渲染,触发第二次查询。
方案1:使用useQuery的enabled选项控制查询时机
通过enabled参数让查询仅在拿到真实的filter值后才执行,这是最推荐的方案,既保留useQuery的缓存和自动更新特性,又能避免无效请求:
const DashboardComponent = () => { // 初始值设为null,标记filter还未从本地存储加载完成 const [filterState, setFilter] = useState(null); const returnFilteredState = async () => { return await localforage.getItem<boolean>('watchedAndReviewedFilterd') || false; }; useEffect(() => { returnFilteredState().then((value) => { setFilter(value); }); }, []); const {error, loading, data: {moviesFromUser: movies} = {}} = useQuery(resolvers.queries.ReturnMoviesFromUser, { variables: { userId: currentUserVar().id, // 兜底使用false,避免filterState为null时变量异常 filter: filterState ?? false, }, // 仅当filterState不为null时,才执行查询 enabled: filterState !== null, }); };
方案2:改用useLazyQuery手动触发查询
先获取到filter值后,再手动调用查询函数,完全掌控查询触发时机:
const DashboardComponent = () => { const [filterState, setFilter] = useState(false); // 初始化useLazyQuery,拿到手动触发查询的函数 const [getMovies, {error, loading, data: {moviesFromUser: movies} = {}}] = useLazyQuery(resolvers.queries.ReturnMoviesFromUser); const returnFilteredState = async () => { const value = await localforage.getItem<boolean>('watchedAndReviewedFilterd') || false; setFilter(value); // 拿到真实filter值后,手动触发查询 getMovies({ variables: { userId: currentUserVar().id, filter: value, }, }); }; useEffect(() => { returnFilteredState(); }, []); };
方案3:同步获取本地存储值(仅适用于非异步存储API)
如果可以替换localforage为同步的localStorage,可以直接在组件初始化时获取filter值,避免异步状态更新触发重渲染:
const DashboardComponent = () => { // 同步获取本地存储值,直接作为初始状态 const filterState = JSON.parse(localStorage.getItem('watchedAndReviewedFilterd') || 'false'); const {error, loading, data: {moviesFromUser: movies} = {}} = useQuery(resolvers.queries.ReturnMoviesFromUser, { variables: { userId: currentUserVar().id, filter: filterState, }, }); };
内容的提问来源于stack exchange,提问作者Peter Boomsma
相关产品推荐
相关产品推荐

