T
TanStack•12mo ago
fascinating-indigo

Using react query cache enough for my use case, or do I need to include a state management lib?

Hey all! Let me first simplify my use-case using some pseudo code:
const ChatManager = () => {
return (
<>
<ChatQuestion/>
<FollowUp1/>
<FollowUp2/>
<ChatResult/>
</>
);
};
const ChatManager = () => {
return (
<>
<ChatQuestion/>
<FollowUp1/>
<FollowUp2/>
<ChatResult/>
</>
);
};
I am building a simple 'chat' app, actually the user is asked to enter a question initially but that's about it. In the snippet above you can see following components: - ChatQuestion: The only component to initially show to the user, asking for input, calling an API using useMutation - FollowUp1: ONLY shown once the API call within ChatQuestion completed successfully (also using that data). User input required, calling an API using useMutation - FollowUp2: ONLY shown once the API call within FollowUp1 completed successfully (also using that data). User input required, calling an API using useMutation - ChatResult: ONLY shown once the API call within FollowUp2 completed successfully, showing a result to the user. I know react query is basically a async state manager using a map behind the scenes (I just bought the query.gg course 😆). Now I wonder could I implement the logic mentioned above only using react-query, without depending on another state management library like Zustand. I know in an earlier version stuff like this was possible: https://tkdodo.eu/blog/breaking-react-querys-api-on-purpose#state-syncing. To me stuff as mentioned in: https://iamashot.medium.com/supercharge-your-react-state-management-like-a-senior-dev-unlocking-the-power-of-zustand-and-react-b2db33ecd12 seems to be not optimal.
1 Reply
continuing-cyan
continuing-cyan•12mo ago
You could define your mutations inside ChatManager and render FollowUp1, FollowUp2 and ChatResult depending on the state of the mutations
const ChatManager = () => {
const m1 = useChatQuestionMutation(...);
const m2 = useFollowUp1Mutation(...);
const m3 = useFollowUp2Mutation(...);

const shouldShowFollowUp1 = m1.isSuccess;
const shouldShowFollowUp2 = shouldShowFollowUp1 && m2.isSuccess;
const shouldShowChatResult = shouldShowFollowUp2 && m3.isSuccess;

return (
<>
<ChatQuestion mutation={m1} />
{shouldShowFollowUp1 && <FollowUp1 mutation={m2} />}
{shouldShowFollowUp2 && <FollowUp2 mutation={m3} />}
{shouldShowChatResult && <ChatResult />}
</>
);
};
const ChatManager = () => {
const m1 = useChatQuestionMutation(...);
const m2 = useFollowUp1Mutation(...);
const m3 = useFollowUp2Mutation(...);

const shouldShowFollowUp1 = m1.isSuccess;
const shouldShowFollowUp2 = shouldShowFollowUp1 && m2.isSuccess;
const shouldShowChatResult = shouldShowFollowUp2 && m3.isSuccess;

return (
<>
<ChatQuestion mutation={m1} />
{shouldShowFollowUp1 && <FollowUp1 mutation={m2} />}
{shouldShowFollowUp2 && <FollowUp2 mutation={m3} />}
{shouldShowChatResult && <ChatResult />}
</>
);
};
If you're oppossed to passing down the mutations I think you could also use useMutationState. This way you can define call useMutation with a mutationKey inside the components themselves, and look them up through useMutationState to see if it has succeeded
const shouldShowFollowUp1 = useMutationState({ filters: { mutationKey: ['chat-question-mutation'] } }).some(state => state.status === 'success');
const shouldShowFollowUp1 = useMutationState({ filters: { mutationKey: ['chat-question-mutation'] } }).some(state => state.status === 'success');

Did you find this page helpful?