当来自 Apollo useQuery 挂钩的“数据”返回 useMemo 所依赖的“数据”的新值时,useMemo 未运行

Posted

技术标签:

【中文标题】当来自 Apollo useQuery 挂钩的“数据”返回 useMemo 所依赖的“数据”的新值时,useMemo 未运行【英文标题】:useMemo not running when "data" from Apollo useQuery hook returns a new value for "data" on which useMemo is dependent 【发布时间】:2021-10-21 12:06:48 【问题描述】:

我有一个组件,它使用 useQuery Apollo Hook 从 GraphQL API 获取数据。该组件还有一个 useMemo,它具有从 useQuery Apollo 挂钩返回的数据变量作为依赖项。 useMemo 最初在组件的第一次渲染上运行,因为它应该。然后,当来自 useQuery 的数据返回时,它再次运行。我通过对 useQuery 中的数据变量进行一些更改来跟进这一点。

现在,当我在另一个选项卡中重新渲染此组件时,useQuery 在初始渲染时运行一次,这是应该的,但当来自 useQuery 的数据返回时不会再次运行。 注意:我在上一个选项卡中修改了 useMemo 中的数据变量,graphql api 返回了一个新的数据值,所以 useMemo 应该能够发现它,但不知何故它没有。

我调查的可能原因:

    useMemo 只会在第二个选项卡中第二次运行,如果“数据”变量处于函数状态,并且当来自 useQuery 的新数据返回并且 useQuery 重新呈现组件时不会运行,因为它没有变化的可见性。

任何帮助将不胜感激。谢谢!

functional component: 
  const  data, loading, error: loadRolesError  = useQuery();

  const result = useMemo(()=>
    // changing data inside here
  , [data])

【问题讨论】:

什么?使用效果,不是备忘录...单独的选项卡=单独的状态/实例...您无法更改加载的数据,apollo返回只读数据...准备更真实和可编辑的minimal reproducible example和更详细的描述? 嘿,谢谢你回来 - 我找到了问题,错误的原因如下 - 我的组件中发生的问题是我正在更改从 useQuery 返回的“数据”值直接在我的组件逻辑中挂钩。 useMemo 没有运行是因为改变了“数据”,这是一个直接在 React 知识之外的状态变量。而且我还确认 useQuery 在数据更改时成功地重新渲染了我的组件。 并且单独的选项卡共享相同的状态,因为数据是一个对象并且它们是通过引用复制的。我直接修改它而不使用useEffect。所以它被分享了。 【参考方案1】:

我会在这个用例中使用 Apollo 的 useReactiveVar 钩子。来自文档With the useReactiveVar hook, React components can also include reactive variable values in their state directly, without wrapping them in a query.

这有几个部分,所以我在下面草拟了一个解决方案,它为所有部分提供了导入声明和从依赖项开始的可能实现

import React,  useEffect, useState,  useMemo  from 'react';
import  useReactiveVar, makeVar, useLazyQuery, InMemoryCache  from "@apollo/client"; 

制作 apollo 缓存变量

   export const dataWillUpdate = 
      // some nice flat schema data object,
      niceFlatSchemaData: 
      ;
   const dataWillUpdateVar = makeVar(dataWillUpdate);
const component = () => 
    // make the reactive apollo variable
    const dataWillUpdateVarReactive = useReactiveVar(dataWillUpdateVar);
    // memo the niceFlatSchemaData data object
    const niceFlatSchemaData = useMemo(() => userProfileVarReactive.niceFlatSchemaData, [
        dataWillUpdateVarReactive.niceFlatSchemaData,
    ]);
    // see 2 for lazy queries
    const [ getData,  data, loading, error: loadRolesError ] = useLazyQuery();  


    useEffect(() => 
        // will update here when change to niceFlatSchemaData
        // so run query here
        getData(variables:input:
            // nice flat input object for the gql
        )
    , [niceFlatSchemaData])

    useEffect(() => 
        // will update here when quer calls back
        // state changes for render
     
    , [data])


需要在 apollo 缓存中配置变量

const globalCache = new InMemoryCache(

    typePolicies: 
        Query: 
            fields: 
                dataWillUpdate: 
                    read() 
                        return dataWillUpdateVar();
                    ,
                ,
            ,
        ,
    ,
);

[1]useReactiveVar [2]lazy query

【讨论】:

感谢您的详细回复。我的组件中发生的问题是我直接在我的组件逻辑中更改了从 useQuery 挂钩返回的“数据”值。 useMemo 没有运行是因为改变了“数据”,这是一个直接在 React 知识之外的状态变量。而且我还确认 useQuery 在数据更改时成功地重新渲染了我的组件。

以上是关于当来自 Apollo useQuery 挂钩的“数据”返回 useMemo 所依赖的“数据”的新值时,useMemo 未运行的主要内容,如果未能解决你的问题,请参考以下文章

Apollo 客户端没有读取使用 useQuery 钩子传入的变量

Apollo 客户端 fetchMore 来自 useQuery 触发两个网络请求

无法使用 useQuery 挂钩为具有一些 @client 变量的远程查询获取数据

来自 apollo react 的 useQuery 方法的意外结果

react native apollo client useQuery invalid hook call error

在 apollo graphql 的单个 useEffect 挂钩中使用多个查询