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

封装自定义Apollo Hook时useLazyQuery触发旧变量问题咨询

分析与解决方案

Let's break down each issue you're facing and fix your custom Apollo Hook step by step:

1. Why refetch uses old date parameters

The core problem here stems from unnecessary local state duplication and a subtle quirk in how Apollo handles refetch variables. Your Hook syncs Apollo's data to a local something state via useEffect, which creates a potential sync delay. Additionally, even with fetchPolicy: 'no-cache', Apollo may retain the initial query variables internally if your refetch variable structure isn't explicitly matching what the query expects—this can cause it to fall back to old values.

2. Unwanted old requests with fetchMore

fetchMore is designed for pagination or appending data to an existing result set, not for fetching entirely new data with updated parameters. Using it here confuses Apollo's cache management: it tries to merge new data with old entries, leading to unexpected stale requests as it holds onto previous variable values.

3. Duplicate requests when using getSomething

This happens because your local something state triggers component re-renders whenever it updates. If your component re-renders while a query is in flight, or if the useMemo dependency array causes the Hook's returned values to refresh, it can accidentally trigger a second getSomething call. Maintaining a separate state also creates redundant sync work that Apollo can handle natively.


Fixed Custom Hook Implementation

The key fix is to remove the local something state and rely directly on Apollo's built-in query state. This eliminates sync issues and redundant requests:

import { useLazyQuery, useCallback, useMemo } from '@apollo/client';
import { GET_SOMETHING_QUERY } from './your-query-path'; // Adjust import path

// Keep your existing type definitions
type Something = { /* ... */ };
type GetSomethingHook = { something: Something };
type GetSomethingVariables = { args: { id: string; date: Date } };

export const useGetSomething = () => { 
  const [getSomething, { data, refetch, loading, error }] = useLazyQuery<GetSomethingHook, GetSomethingVariables>(
    GET_SOMETHING_QUERY, 
    { fetchPolicy: 'no-cache' } 
  ); 

  // Type-safe load function with explicit variable passing
  const loadSomething = useCallback(
    (id: string, date: Date) => {
      return getSomething({ 
        variables: { args: { id, date } } 
      });
    },
    [getSomething]
  );

  // Simplified refetch with direct variable passing (no local state sync needed)
  const refetchSomething = useCallback(
    (id: string, date: Date) => {
      return refetch({ args: { id, date } });
    },
    [refetch]
  );

  // Memoize returned values to avoid unnecessary component re-renders
  return useMemo(() => {
    return {
      loadSomething,
      refetchSomething,
      something: data?.something,
      loading,
      error
    };
  }, [data, loadSomething, refetchSomething, loading, error]);
};

Key Improvements:

  • Removed local state: We directly use data?.something from Apollo, eliminating the useEffect sync logic and state mismatches.
  • Type safety: Added explicit variable typing to ensure we're passing the exact structure the query expects, preventing silent variable mismatches.
  • Simplified refetch: Apollo automatically updates the data value after refetch, so we no longer need to manually sync to local state.
  • Included standard query states: Added loading and error to make the Hook more usable in components (you can omit these if not needed).

Additional Troubleshooting Tips

  • Verify query variable structure: Double-check that GET_SOMETHING_QUERY expects an args input object matching { id: String!, date: Date! } (or your actual type). Mismatched shapes can cause Apollo to ignore new parameters.
  • Check for unintended re-renders: If you still see duplicate requests, use React DevTools to trace re-renders in the component using this Hook—adjust dependency arrays in parent components to prevent unnecessary refreshes.
  • Stick to refetch for full data refreshes: fetchMore should only be used when appending data to an existing result set, not for fetching entirely new data.

内容的提问来源于stack exchange,提问作者Michał J. Gąsior

火山引擎 最新活动