如何在第一次渲染和点击时都渲染 useQuery? [ReactJS,graphql]

Posted

技术标签:

【中文标题】如何在第一次渲染和点击时都渲染 useQuery? [ReactJS,graphql]【英文标题】:How to render useQuery both on first render and onclick? [ReactJS, graphql] 【发布时间】:2020-10-16 15:46:12 【问题描述】:

如何让我的 useQuery() 在第一次渲染以及后续事件(例如按钮单击)时触发?

根据我的阅读,当 React 首次挂载一个调用 useQuery 的组件时,Apollo 会自动执行查询,如果我想执行该查询以响应事件,我可以改为使用useLazyQuery 返回一个可以调用的函数。如果我想两者都做怎么办?

不太确定我对 React 钩子的哪一部分理解不正确或不完整,但我尝试在 useQuery 中使用 refetch,这绝对允许我调用该函数,但似乎并不总是在组件安装时触发(更令人困惑的是,有时会,有时不会)。我也在使用notifyOnNetworkStatusChange,我读到它需要refetch 来识别它应该触发useQueryonCompleted 部分。

任何帮助将不胜感激,我想我根本不了解 Hooks。谢谢!

附:我的useQuery 的一个例子如下:

const  refetch: refetchGetTaskTypes  = useQuery(GET_TASK_TYPES(["taskId", "taskType"]), 
    notifyOnNetworkStatusChange: true,
    onCompleted: (data) => 
        if (data !== undefined && data.getTaskTypes !== undefined && data.getTaskTypes !== state.taskTypes) 
            dispatch(
                type: 'GET_TASK_TYPES',
                payload: 
                    taskTypes: data.getTaskTypes
                
            );
        
    
);

附言作为refetch 的示例,有时需要调用来渲染而其他时候不需要,我有另一个useQuery,它与上面几乎相同(使用不同的查询)也有refetch,但它首先呈现加载

P.P.P.S.我有时会看到refetch 获取过时数据的另一个问题,我必须使用fetchPolicy: 'cache-and-network' 来修复它。然而,这并不总是发生

【问题讨论】:

使用 useLazyQuery,然后在 useEffect(()->,[]) 中调用它,它将处理您的初始负载。 【参考方案1】:

,但我尝试在 useQuery 中使用 refetch,这绝对允许我调用该函数,但似乎并不总是在组件挂载时触发(更令人困惑的是,有时它会,有时它不会' t)

我怀疑

...网络请求没有被触发? ...或者您的onCompleted 条件不满足(那么没有dispatch)?没有dispatch 并不意味着没有请求/解雇...

onCompleted: (data) => 
    if (data !== undefined && data.getTaskTypes !== undefined && data.getTaskTypes !== state.taskTypes) 

也许你可以删除所有条件:

data 存在时,onCompleted 被触发,无需测试它(data !== undefinedgetTaskTypes 可以为空吗?如果不是(恕我直言,它不应该),也不要测试它; data.getTaskTypes !== state.taskTypes - 为什么不只针对这种类型询问 API?不支持过滤?

你的代码有点混乱

useQuery(GET_TASK_TYPES(["taskId", "taskType"])

它看起来像一些生成器/函数(定义必填字段?) - 改用 const。

还原

看起来您正在使用 redux 来存储接收到的数据。 Apollo 更加智能(规范化缓存)并且不需要为每个数据 [type] 获取编写自定义操作。您应该为此使用 Apollo,但可能您对其进行了测试但失败了? ...

缺少id 字段?

您的任务没有id 字段而是taskId? Apollo 不会将其写入缓存。幸运的是,您可以帮助 Apollo 识别您数据中的唯一标识符 - https://www.apollographql.com/docs/react/caching/cache-configuration/#custom-identifiers

在此之后,您可以简单地使用来自useQuerydata 进行第一次渲染,并在需要/来自事件处理程序时使用refetch(不使用useEffect 挂钩)。

【讨论】:

嗨@xadm,感谢您的回复!我检查了我的 onCompleted (它甚至不会在 if 语句之外触发)。 “请求这种类型的 API”是什么意思?如果这很重要,我正在使用打字稿,所以我需要手动检查类型(否则似乎无法编译)。也不确定“使用 const”是什么意思?最后,关于使用datarefetch,如何使用refetch 更新data 变量?我已经测试过,data 似乎没有更新来自新查询的信息。谢谢! 抱歉忘了说:我没有使用 Redux,我使用的是 Apollo Store。我有一个使用调度解析器等定义的 Store.tsx! 您不应该检查 onCompleted 触发,而是在浏览器开发工具中检查 RAW/JSON 网络请求/响应 .... 要求 API 仅返回某些任务类型(如果有更多任务类型)...如果是一个打字稿,那么您应该使用键入的useQuery 来定义响应数据类型,而不是通过代码检查它... data 应该再次更改,检查网络响应...阿波罗存储?文档/示例? 我也在浏览器中检查了网络,后端数据在那里是正确的,data 不匹配 恕我直言,您应该使用 fetchPolicy: "network-only" 进行此查询【参考方案2】:

使用 LazyQuery -

const [getTaskType,  loading, data ] = useLazyQuery(GET_TASK_TYPE, fetchPolicy: 'network-only'); // fetch policy is to not look for cache and take the data from network only

获取页面加载数据 -

useEffect(() => 
    getTaskType();
, []);

要随时在按钮单击时触发它,您只需调用该方法即可。 -

<Button                                                
  onClick=()=>getTaskType()>Click Me!
</Button>

【讨论】:

谢谢@Dlucidone!这是推荐的方式吗?另外,它是否“反对”任何类型的 react-hooks 规则?据我了解,在钩子中你并没有真正“调用”钩子本身

以上是关于如何在第一次渲染和点击时都渲染 useQuery? [ReactJS,graphql]的主要内容,如果未能解决你的问题,请参考以下文章

在 useQuery 后反应组件不重新渲染

react-query:useQuery 返回 undefined 并且组件不会重新渲染

如何使用 useQuery 钩子在其他钩子中填充状态?

状态变化时如何防止 useQuery 运行?

如何避免在反应功能组件中对“静态组件”进行不必要的重新渲染?

如何在 x 时间后重新渲染反应(突变阿波罗)