You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Apollo Client响应式变量更新后查询未自动刷新的问题排查

Apollo Client响应式变量更新后查询未自动刷新的问题排查

哎,我瞅了你的代码,发现两个核心问题导致点击“Load More”后查询没自动刷新,咱们一步步来解决:

问题1:响应式变量定义在组件内部,每次渲染都重建

你现在把makeVar放在了RecipeList组件函数里,这意味着每次组件重新渲染时,都会创建全新的queryLimitpagerOffset变量。之前更新的变量和useQuery绑定的根本不是同一个实例,自然不会触发查询更新。

问题2:组件没订阅响应式变量的变化

你的useQuery里的variables是直接调用queryLimit()pagerOffset()获取初始值,但组件并没有订阅这些变量的变化——变量更新时,组件不会重新渲染,useQuery也就不知道要重新执行查询。


修正后的完整代码

第一步:App.js(原代码逻辑没问题,确认即可)

// App.js
import { InMemoryCache } from '@apollo/client';
import { offsetLimitPagination } from "@apollo/client/utilities";

const queryCache = new InMemoryCache({
  typePolicies: {
    Query: {
      fields: {
        entries: offsetLimitPagination(["section"]) // 与查询的section变量对应,缓存策略正确
      }
    }
  }
});

第二步:重构RecipeList.js

// RecipeList.js
import { makeVar, useQuery, gql, useReactiveVar } from '@apollo/client';

// !!关键:把响应式变量移到组件外部,确保全局唯一实例
export const queryLimit = makeVar(12);
export const pagerOffset = makeVar(0);

const GET_RECIPE_ENTRIES = gql`
  query GetRecipeEntries(
    $section: [String]
    $limit: Int
    $offset: Int
  ) {
    recipeList: entries(
      section: $section
      limit: $limit
      offset: $offset
    ) {
      id
      title
      uri
      ... on recipes_recipes_Entry {
        recipeImg {
          url
        }
      }
    }
  }
`;

export default function RecipeList() {
  // 用useReactiveVar订阅变量变化,变量更新时组件自动重新渲染
  const limit = useReactiveVar(queryLimit);
  const offset = useReactiveVar(pagerOffset);

  const { data } = useQuery(GET_RECIPE_ENTRIES, {
    variables: {
      section: ["recipes"],
      limit, // 使用订阅后的实时变量值
      offset,
    },
    // 可选:如果需要强制每次变量变化都请求后端(而非仅读缓存),可以添加
    // fetchPolicy: 'cache-and-network'
  });

  const renderRecipeList = () => {
    if (data) {
      return (
        <ul>
          {data.recipeList.map((recipe) => (
            <li key={recipe.id}>
              <a href={recipe.uri}>
                <h3>{recipe.title}</h3>
                <img src={recipe.recipeImg[0].url} alt={recipe.title} />
              </a>
            </li>
          ))}
        </ul>
      );
    }
  };

  const handleClick = () => {
    // 更新响应式变量,组件会因useReactiveVar的订阅自动重新渲染,触发useQuery执行新查询
    pagerOffset(pagerOffset() + queryLimit());
  };

  const renderMoreButton = () => {
    return <button onClick={handleClick}>Load More</button>;
  };

  return (
    <div>
      {renderRecipeList()}
      {renderMoreButton()}
    </div>
  );
}

为啥这样改就生效?

  1. 响应式变量全局化:放在组件外后,整个应用生命周期内只会创建一次,更新和查询用的是同一个变量实例。
  2. useReactiveVar订阅变化useReactiveVar会让组件监听响应式变量的更新,变量一变,组件就重新渲染,useQuery检测到variables里的limit/offset值变化,就会自动执行新的查询。
  3. 你的offsetLimitPagination缓存策略是对的,它会帮你把新分页的条目合并到缓存里,不会覆盖之前的结果。

额外小提示

如果需要在其他组件里控制分页(比如顶部的分页器组件),直接导入queryLimitpagerOffset,调用queryLimit(newLimit)或者pagerOffset(newOffset)就能更新,RecipeList组件会自动响应变化~

内容来源于stack exchange

火山引擎 最新活动