封装自定义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?.somethingfrom Apollo, eliminating theuseEffectsync 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
datavalue after refetch, so we no longer need to manually sync to local state. - Included standard query states: Added
loadinganderrorto 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_QUERYexpects anargsinput 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
refetchfor full data refreshes:fetchMoreshould only be used when appending data to an existing result set, not for fetching entirely new data.
内容的提问来源于stack exchange,提问作者Michał J. Gąsior




