如何在Next.js的useEffect中实现Apollo useQuery并更新页面数据?
问题翻译
我正在使用Apollo获取数据,希望页面重新渲染时能展示新数据,请问如何在Next.js的useEffect中实现Apollo useQuery?
解决方案
首先明确:React Hooks(包括useQuery)不能直接在useEffect内部调用——Hooks必须遵循调用规则,只能在组件顶层或自定义Hook中执行。你不需要把useQuery放进useEffect,而是利用Apollo内置的刷新机制来实现需求,以下是几种可行方案:
方案1:用refetch手动触发数据刷新
通过解构useQuery返回的refetch方法,配合useEffect监听依赖变化,在需要时重新获取数据(比如用户创建成功后)。
修改后的代码示例:
import { GET_ALL_USERS } from "@/graphql/queries" import { useQuery } from "@apollo/client" import { useEffect, useState } from "react"; export default function Home() { // 解构出refetch方法 const { data, loading, refetch } = useQuery(GET_ALL_USERS); // 用状态标记是否需要刷新数据 const [shouldRefetch, setShouldRefetch] = useState(false); // 监听状态变化,触发数据刷新 useEffect(() => { if (shouldRefetch) { refetch(); setShouldRefetch(false); // 重置状态 } }, [shouldRefetch, refetch]); // 传递给CreateUser组件的回调:创建成功后标记需要刷新 const handleUserCreated = () => { setShouldRefetch(true); }; return ( <> <CreateUser onUserCreated={handleUserCreated} /> {loading ? <span>加载数据中,请稍候...</span> : data?.getAllUsers.map((user: any, index: any) => { // 优先用user.id作为key,避免index带来的问题 return <div key={user.id || index}>{user.name} {user.username}</div> }) } </> ) }
方案2:设置pollInterval自动轮询
如果需要定期自动刷新数据,给useQuery添加pollInterval参数(单位:毫秒),即可实现定时重新获取数据:
const { data, loading } = useQuery(GET_ALL_USERS, { pollInterval: 5000, // 每5秒自动刷新一次数据 });
方案3:更新Apollo缓存自动触发重渲染
当通过useMutation创建用户时,在mutation的update函数中直接更新缓存,useQuery会自动检测到缓存变化,触发组件重渲染,无需手动发起请求。
示例(CreateUser组件内部的mutation逻辑):
import { CREATE_USER } from "@/graphql/mutations"; import { useMutation } from "@apollo/client"; import { GET_ALL_USERS } from "@/graphql/queries"; function CreateUser() { const [createUser] = useMutation(CREATE_USER, { update(cache, { data: { createUser } }) { // 读取当前缓存中的用户列表 const { getAllUsers } = cache.readQuery({ query: GET_ALL_USERS }); // 将新用户写入缓存,触发useQuery更新 cache.writeQuery({ query: GET_ALL_USERS, data: { getAllUsers: [...getAllUsers, createUser] }, }); }, }); // 创建用户的表单逻辑... }
关键提示
- 不要尝试在
useEffect内部调用useQuery,这违反React Hooks规则会导致报错。 - 优先选择缓存更新的方式,性能更优;若必须重新获取数据,使用
refetch配合状态监听的方案。
内容的提问来源于stack exchange,提问作者erwin
相关产品推荐
相关产品推荐

