React Apollo自动缓存更新失效咨询:列表场景下的缓存同步问题
Hey there! Great question—this is a super common gotcha with React Apollo's cache behavior. Let me break it down for you:
Short Answer
By default, the automatic cache update won't work for objects inside a list in the scenario you described. Here's why, and how to fix it:
Why It Doesn't Work
React Apollo's automatic cache updates rely on unique object identifiers (usually the id field, or a custom ID you configure) to match and update cached objects. When you run a mutation that updates a single object, Apollo can find that object in the cache using its ID and update it.
But for lists? Apollo doesn't automatically scan every cached list to find where that updated object is referenced—unless you explicitly tell it to make that connection.
Fixes to Get Automatic (or Manual) Updates
1. Use the update Function to Manually Update the List
This is the most direct way to handle it: you write a custom function that finds the list in the cache, replaces the updated item, and writes the new list back.
Example code:
const [updateReview] = useMutation(UPDATE_REVIEW_MUTATION, { update(cache, { data: { updateReview } }) { // Read the current review list from cache const { reviewList } = cache.readQuery({ query: REVIEW_LIST_QUERY, variables: { model: 12 } // Match the variables used in your original list query }); // Replace the old review with the updated one in the list const updatedList = reviewList.list.map(review => review.reviewId === updateReview.reviewId ? updateReview : review ); // Write the updated list back to cache cache.writeQuery({ query: REVIEW_LIST_QUERY, variables: { model: 12 }, data: { reviewList: { ...reviewList, list: updatedList } } }); } });
2. Configure dataIdFromObject for Universal Object Identification
This is the most elegant long-term solution. By defining how Apollo generates unique IDs for all your object types, you let Apollo automatically link updates to any place the object is referenced—including lists.
When you create your Apollo Client, add this configuration:
import { ApolloClient, InMemoryCache, defaultDataIdFromObject } from '@apollo/client'; const client = new ApolloClient({ uri: '/your-graphql-endpoint', cache: new InMemoryCache({ dataIdFromObject: object => { switch (object.__typename) { case 'Review': return `Review:${object.reviewId}`; // Use reviewId as the unique key for Review type case 'Post': return `Post:${object.id}`; // Example for other types default: return defaultDataIdFromObject(object); // Fallback to default for other types } } }) });
Important: Make sure your mutation returns the updated Review object with both __typename and reviewId—this is how Apollo matches it to the cached object and updates all references (including your list).
3. Refetch the List Query (Quick and Simple)
If you don't want to mess with cache logic, you can just tell Apollo to re-run the list query after the mutation finishes. This pulls fresh data from the server and updates the cache automatically.
Example:
const [updateReview] = useMutation(UPDATE_REVIEW_MUTATION, { refetchQueries: [ { query: REVIEW_LIST_QUERY, variables: { model: 12 } } // Specify the list query to refetch ] });
Note: This is less efficient than the other methods since it makes an extra network call, but it's great for quick fixes or simple use cases.
Wrap-Up
The core issue is that Apollo needs explicit instructions to connect single-object mutations to list-based queries. Pick the method that fits your project's needs—dataIdFromObject is ideal for scaling, while update gives you full control, and refetchQueries is the fastest to implement.
内容的提问来源于stack exchange,提问作者RedGiant

