Fullstack CourseLearn by building
Back to week 4

Topic

Challenge: Query or RTK?

Definition

TanStack Query manages server-owned asynchronous data, whereas Redux Toolkit manages shared client-owned state that has no server cache as its source of truth.

In simpler words

Feed posts come from Nest through Query; a half-written post belongs in the RTK draft slice.

The wrong split creates duplicated post arrays and manual synchronization bugs.

After this you can

  • Classify server versus client state
  • Invalidate instead of manually mirroring server arrays

Choose one source of truth

Definition

A server-state cache must remain authoritative for remote entities, while client state should represent only local UI information.

In simpler words

Do not keep the same feed collection in both Query and Redux.

Store composer text and local UI preferences in RTK.

Use a mutation then invalidate the feed key after Nest accepts a post.

Keep in mind

  • Ask “could another user change this on the server?” before choosing RTK.

Challenge lab

Bug report

New posts appear twice after a create succeeds.

What is broken

The submit handler pushes the server result into a Redux feed array and invalidates the Query feed.

Broken snippet

onSuccess(post) {
  dispatch(feedActions.push(post)); // second copy
  queryClient.invalidateQueries({ queryKey: ["feed"] });
}

Pass criteria

  • One feed source of truth
  • Draft clears after confirmed success
  • Feed refreshes after create

Checking your session…

Choose the correct fix

Test

Check your understanding

At least 10 questions — mix of concept, syntax, practical, and logic. Score ≥80% (enforced by the API) to save progress.

Checking your session…

15 questions · concept 5 · syntax 3 · practical 4 · logic 3

1. How should the Query/RTK challenge split state?
Concept
2. After a successful create mutation?
Syntax
3. Draft title while editing?
Practical
4. Why not duplicate Query data into RTK by default?
Logic
5. Cookies with Axios + Query?
Concept
6. Optimistic update caution?
Practical
7. Selector for draft slice?
Syntax
8. Loading and error UX?
Logic
9. When is RTK the wrong tool?
Concept
10. Challenge done means?
Practical
11. Why invalidate after the create?
Conceptintermediate
useMutation({
  mutationFn: createNote,
  onSuccess: () => qc.invalidateQueries({ queryKey: ['notes'] }),
});
12. What rule does this violate?
Syntaxadvanced
const { data } = useQuery({ queryKey: ['notes'], queryFn });
dispatch(notes.setAll(data));
13. What belongs in RTK here?
Practicalintermediate
const title = useAppSelector(s => s.noteDraft.title);
const onChange = (e) => dispatch(setTitle(e.target.value));
14. What must you also handle for a safe optimistic update?
Logicadvanced
onMutate: async (newNote) => {
  await qc.cancelQueries({ queryKey: ['notes'] });
  qc.setQueryData(['notes'], old => [...old, newNote]);
}
15. How should the UI use these flags?
Conceptintermediate
const { data, isLoading, isError } = useQuery(/* ... */);

Checking your session…