为何Query组件内嵌套的Mutation的onCompleted回调无法触发?
Great question! Let’s walk through the most likely reasons your CREATE_ITEM mutation’s onCompleted callback isn’t firing when nested inside your GET_SEQUENCE Query component, along with fixes for each scenario:
1. Your Mutation component might not be mounting at all
The most common culprit here is unhandled loading/error states in the parent Query component. When the Query is still fetching data (loading: true), data.sequence will be undefined. Trying to access sequence.items.length in this state will throw an error, preventing the Mutation component from ever rendering.
Fix: Explicitly handle loading and error states before checking the item count:
<Query query={GET_SEQUENCE} variables={{ id: sequenceId }}> {({ loading, error, data }) => { if (loading) return <div>Loading sequence...</div>; if (error) return <div>Failed to load sequence: {error.message}</div>; const sequence = data?.sequence; // Only render Mutation if sequence exists AND has no items if (!sequence || sequence.items.length === 0) { return ( <Mutation mutation={CREATE_ITEM} onCompleted={createItemOpts.onCompleted} > {(createItem) => ( <button onClick={() => createItem({ variables: { /* your item data */ } })}> Add First Item </button> )} </Mutation> ); } return <div>Sequence has {sequence.items.length} items</div>; }} </Query>
2. The mutation isn’t actually being executed
Rendering the Mutation component doesn’t run the mutation—you have to explicitly call the mutate function it provides (usually via a button click or similar trigger). If you’re not invoking this function, onCompleted will never fire.
Double-check:
- Make sure you’re using the mutate function returned by the Mutation component’s render prop.
- Verify there’s no logic blocking the trigger (e.g., disabled buttons, event.preventDefault() being misused).
3. The mutation is failing silently
If the mutation throws an error (e.g., invalid variables, server-side issues), onCompleted won’t run—but if you haven’t added an onError callback, you’ll never see the error.
Fix: Add an onError handler to debug:
<Mutation mutation={CREATE_ITEM} onCompleted={createItemOpts.onCompleted} onError={(error) => console.error("Mutation failed:", error)} > {/* ... */} </Mutation>
Check your browser console for GraphQL errors or network issues that might be stopping the mutation from completing successfully.
4. The Mutation component unmounts before onCompleted fires
If the parent Query component re-renders and unmounts the Mutation (e.g., if another update changes sequence.items.length mid-mutation), the onCompleted callback will be canceled before it can run.
Debug:
- Use React DevTools to watch if the Mutation component unmounts while the mutation is in flight.
- Consider moving the Mutation component outside the Query’s render prop if it doesn’t depend on the Query’s data directly, or use state to control its visibility more explicitly.
5. Scope/binding issues with createItemOpts.onCompleted
If createItemOpts.onCompleted is undefined, or if it’s a function that’s being recreated every render (leading to stale references), it might not execute as expected.
Test: Replace the callback with an inline function to rule out scope issues:
<Mutation mutation={CREATE_ITEM} onCompleted={(mutationData) => { console.log("Mutation completed successfully!", mutationData); // Add your original onCompleted logic here temporarily }} > {/* ... */} </Mutation>
If this works, check how createItemOpts is defined—make sure the function is stable (e.g., use useCallback if it’s defined inside a component).
内容的提问来源于stack exchange,提问作者Jaakko Karhu

