Deck 5 - Server State + React Query v5 Flashcards

Query keys, enabled/dependent queries, cache + staleTime/gcTime, mutations, invalidation, optimistic updates. (80 cards)

1
Q

Deck 5 - Server State + React Query v5 (objective)

A

Goal: evaluate async data fetching and server-state patterns (cache, retries, invalidation, optimistic updates).
You practice: query keys, enabled/dependent queries, error/loading states, and avoiding redundant local state.
Output style: 1 verdict sentence + 2-3 issues + best fix approach.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

Server state vs client state (definition).

A
  • Server state: fetched/derived from backend (cacheable, stale).
  • Client state: UI-only (open/closed, input text).
  • Rule: do not mirror server state into local state without a reason.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

React Query: queryKey (why).

A
  • queryKey uniquely identifies cached data.
  • Must include all inputs (id, filters) that change the result.
  • Use stable, serializable keys.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

Query function contract (baseline).

A
  • queryFn should return data or throw on error.
  • Prefer fetch with res.ok check.
  • Support AbortSignal when possible.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

staleTime (what it controls).

A
  • How long cached data is considered fresh.
  • Fresh data avoids refetch on mount/focus.
  • Tune to reduce churn for slow-changing data.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

gcTime/cacheTime (what it controls).

A
  • How long unused cache remains before garbage collected.
  • v5 uses gcTime naming; older docs say cacheTime.
  • Longer gcTime helps back/forward navigation.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

isLoading vs isFetching (difference).

A
  • isLoading: first load with no data.
  • isFetching: any background refetch.
  • UI: show spinner only when loading, not always when fetching.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

enabled (why/when).

A
  • Prevent query from running until inputs are ready.
  • Use for optional params and dependent queries.
  • Avoid fetches with undefined ids.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

Dependent queries (pattern).

A
  • Query B depends on data from Query A.
  • Use enabled: !!dep.
  • Keep keys distinct and include dep input.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

Pagination and keepPreviousData (pattern).

A
  • Keep old page data while fetching next.
  • Reduces UI flicker.
  • Combine with stable key including page param.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

Infinite queries (baseline).

A
  • Use useInfiniteQuery for cursor pagination.
  • Implement getNextPageParam correctly.
  • Avoid mixing manual page state with infinite pages.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

Mutations (baseline).

A
  • useMutation for create/update/delete.
  • On success: invalidateQueries or update cache.
  • Handle pending/error states intentionally.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

invalidateQueries vs refetchQueries.

A
  • invalidate marks stale and refetches on next usage (or immediately based on config).
  • refetch triggers immediate fetch.
  • Prefer invalidate for cache coherence.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

setQueryData (when).

A
  • Update cache directly for optimistic UI or small updates.
  • Must keep shape consistent.
  • Avoid partial/incorrect cache shapes.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

Optimistic updates (pattern).

A
  • onMutate: snapshot previous cache, apply optimistic change.
  • onError: rollback.
  • onSettled: invalidate/refetch to reconcile.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

Retry behavior (gotcha).

A
  • Retries can hide errors in UI.
  • Tune retry count and retryDelay.
  • Consider turning off retries for 4xx errors.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
17
Q

Error boundaries and suspense (overview).

A
  • React Query can integrate with Suspense and Error Boundaries.
  • If not using, handle error via status + messages.
  • Keep UX consistent across screens.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
18
Q

Prefetching (why).

A
  • Prefetch likely-next data to improve perceived speed.
  • Use queryClient.prefetchQuery.
  • Do not prefetch everything (wasteful).
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
19
Q

Abort/cancellation (best practice).

A
  • Pass signal to fetch to cancel in-flight requests.
  • Prevents wasted work and race issues.
  • Avoid setState after unmount patterns (React Query helps).
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
20
Q

Anti-pattern: useEffect fetch + React Query together.

A
  • Pick one source of truth.
  • Do not fetch twice.
  • Do not copy query data into local state unless editing locally.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
21
Q

Gotcha: queryKey missing parameter.

useQuery({
  queryKey: ['user'],
  queryFn: () => fetch(`/api/users/${id}`).then(r => r.json()),
});
A

Verdict: FAIL
- Issue: queryKey does not include id.
- Impact: cache collisions (wrong user shown).
- Fix: queryKey: [‘user’, id] and validate id.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
22
Q

Gotcha: query runs with undefined id.

useQuery({ queryKey: ['user', id], queryFn: () => fetch(`/api/users/${id}`) });
A

Verdict: FAIL
- Issue: id may be undefined/empty.
- Fix: enabled: !!id and guard in queryFn.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
23
Q

Gotcha: queryKey missing filter/sort.

useQuery({ queryKey: ['items'], queryFn: () => fetch(`/api/items?sort=${sort}`) });
A

Verdict: FAIL
- Issue: inputs not in key (cache collision).
- Fix: include sort/filter in queryKey.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
24
Q

Gotcha: unstable object in queryKey.

useQuery({ queryKey: ['search', { q }], queryFn: ... });
A

Verdict: PARTIAL FAIL
- Issue: object identity can change; refetch churn.
- Fix: use primitives ([‘search’, q]) or stable serialization.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
25
Gotcha: queryFn does not throw on bad status. ``` const data = await fetch(url).then(r => r.json()); ```
Verdict: FAIL - Issue: res.ok not checked. - Fix: if (!res.ok) throw; then json.
26
Gotcha: mirroring query data into local state. ``` const q = useQuery(...); const [user, setUser] = useState(null); useEffect(() => setUser(q.data), [q.data]); ```
Verdict: FAIL - Issue: duplicate source of truth. - Fix: render from q.data unless editing locally.
27
Gotcha: showing spinner during background refetch. ``` if (query.isFetching) return ; ```
Verdict: PARTIAL FAIL - Issue: isFetching includes background refetch. - Fix: use isLoading for initial load; keep data visible while fetching.
28
Gotcha: mutation without invalidation.
Verdict: FAIL - Issue: cache not updated. - Fix: invalidateQueries or setQueryData on success.
29
Gotcha: invalidating wrong key namespace. ``` queryClient.invalidateQueries({ queryKey: ['user'] }); ```
Verdict: PARTIAL FAIL - Issue: may not match actual keys. - Fix: invalidate correct namespace or target exact key.
30
Gotcha: optimistic update without rollback. ``` onMutate: async (input) => { queryClient.setQueryData(['todos'], (old) => [...old, input]); } ```
Verdict: FAIL - Issue: no snapshot/rollback. - Fix: snapshot previous cache and restore in onError.
31
Gotcha: stale closure in mutation callbacks. ``` const [filter] = useState('all'); useMutation({ onSuccess: () => invalidate(['items', filter]) }); ```
Verdict: PARTIAL FAIL - Issue: callback may capture stale values. - Fix: compute keys from mutation variables/callback args.
32
Gotcha: retrying 404/400 errors.
Verdict: PARTIAL FAIL - Issue: retries waste time. - Fix: disable retry for 4xx or use retry function.
33
Gotcha: non-serializable queryKey. ``` useQuery({ queryKey: ['x', new Date()], queryFn: ... }); ```
Verdict: FAIL - Issue: unstable key. - Fix: use ISO string/timestamp.
34
Gotcha: dependent query missing enabled. ``` const user = useQuery(...); useQuery({ queryKey: ['posts', user.data.id], queryFn: ... }); ```
Verdict: FAIL - Issue: user.data may be undefined. - Fix: enabled: !!user.data?.id.
35
Gotcha: key collision across resources. ``` useQuery({ queryKey: ['items', id], queryFn: fetchUsers }); useQuery({ queryKey: ['items', id], queryFn: fetchOrders }); ```
Verdict: FAIL - Issue: same key for different resources. - Fix: namespace keys per resource.
36
Gotcha: cache updated with wrong shape.
Verdict: FAIL - Issue: setQueryData writes invalid shape. - Fix: keep types aligned and do not store invalid values.
37
Gotcha: queryFn returns Response not data. ``` queryFn: () => fetch(url) ```
Verdict: FAIL - Issue: consumer expects parsed data. - Fix: parse json and return data (throw on !ok).
38
Gotcha: setState inside queryFn.
Verdict: FAIL - Issue: side effects inside queryFn. - Fix: keep queryFn pure; return data and render from query.
39
Gotcha: invalidating too broadly.
Verdict: PARTIAL - Issue: network storm. - Fix: invalidate targeted keys only.
40
Gotcha: not disabling submit during mutation.
Verdict: PARTIAL - Issue: double-submit risk. - Fix: disable while pending and show progress.
41
Gotcha: empty state vs error conflated.
Verdict: PARTIAL - Issue: empty list treated like failure. - Fix: empty is success with empty UI; error is alert + retry.
42
Gotcha: ignoring AbortSignal. ``` queryFn: ({ signal }) => fetch(url).then(r => r.json()) ```
Verdict: PARTIAL - Issue: signal not passed to fetch. - Fix: fetch(url, { signal }).
43
Gotcha: missing encodeURIComponent. ``` fetch(`/api/search?q=${q}`) ```
Verdict: PARTIAL - Fix: encodeURIComponent(q).
44
Gotcha: refetchOnWindowFocus surprises.
Verdict: PARTIAL - Issue: focus refetch churn. - Fix: tune refetchOnWindowFocus.
45
Gotcha: polling everywhere.
Verdict: PARTIAL FAIL - Issue: refetchInterval can be expensive. - Fix: poll only when needed; disable when hidden.
46
Gotcha: infinite query missing getNextPageParam.
Verdict: FAIL - Fix: implement getNextPageParam from cursor/next token.
47
Gotcha: keepPreviousData missing for pagination.
Verdict: PARTIAL - Issue: flicker. - Fix: keep previous/placeholder data.
48
Gotcha: select mutates cached object.
Verdict: FAIL - Issue: select should be pure. - Fix: return derived value without mutation.
49
Gotcha: prefetch everything.
Verdict: PARTIAL FAIL - Issue: wastes bandwidth. - Fix: prefetch only likely-next routes.
50
Gotcha: sensitive data fetched in browser.
Verdict: PARTIAL FAIL - Issue: client fetch can expose payload. - Fix: fetch on server or ensure auth + least privilege.
51
Gotcha: mutation error not surfaced.
Verdict: FAIL - Fix: show visible mutation error and allow retry.
52
Gotcha: invalidation mismatch due to exact matching.
Verdict: PARTIAL - Fix: use partial key (exact:false) or target exact keys.
53
Gotcha: queryKey includes functions.
Verdict: FAIL - Issue: non-serializable key. - Fix: remove functions from key.
54
Gotcha: staleTime too low for stable data.
Verdict: PARTIAL - Fix: raise staleTime for slow-changing resources.
55
Gotcha: combining manual fetch and React Query.
Verdict: FAIL - Issue: double fetch + conflicting state. - Fix: pick one source of truth (React Query).
56
Gotcha: using Redux to store server cache.
Verdict: PARTIAL FAIL - Issue: duplicates cache responsibilities. - Fix: keep server state in React Query.
57
Gotcha: mutation update races.
Verdict: PARTIAL - Fix: reconcile using server response; serialize if needed.
58
Gotcha: isLoading hides cached data.
Verdict: PARTIAL - Fix: show data when present; treat isFetching as background refresh.
59
Gotcha: query.data! non-null assertion in render.
Verdict: PARTIAL FAIL - Fix: guard on data/status; avoid !.
60
Gotcha: error UI not accessible.
Verdict: PARTIAL - Fix: use role='alert' or ErrorBoundary integration.
61
Scenario: verdict + 3 issues. ``` useQuery({ queryKey: ['user'], queryFn: () => fetch(`/api/users/${id}`).then(r => r.json()) }); ```
Verdict: FAIL 1) key missing id (cache collision) 2) no res.ok check/throw 3) missing enabled/guard for id
62
Scenario: best fix for query that depends on userId.
Include userId in queryKey and set enabled: !!userId; validate response and handle errors.
63
Scenario: correct UI for background refetch.
Keep showing prior data; show subtle refresh indicator using isFetching; avoid full spinner.
64
Scenario: mutation updates list - what to do?
Invalidate list query on success or update cache with setQueryData; do not leave stale list.
65
Scenario: optimistic update steps (minimal).
snapshot previous -> apply optimistic cache update -> rollback on error -> invalidate on settled.
66
Scenario: avoid refetch churn for stable data.
Increase staleTime and tune refetchOnWindowFocus; prefetch likely paths.
67
Scenario: queryKey design rule.
Keys must uniquely identify resource and include all inputs; avoid collisions and non-serializable parts.
68
Scenario: when not to mirror query.data to local state.
When not editing locally; use query.data directly to avoid duplicate sources of truth.
69
Scenario: enabled usage (why).
Use enabled to prevent requests with missing params and to create dependent queries.
70
Scenario: safest fetch parsing approach.
Check res.ok; throw on errors; parse json; treat external data as unknown if shape matters.
71
Scenario: empty list vs error.
Empty list is success with empty UI; error is failure with alert/message and retry.
72
Scenario: prevent double submit on mutation.
Disable controls while pending; show progress; show error on failure; allow retry.
73
Scenario: stale closure in onSuccess - fix.
Use mutation variables/callback args to compute invalidation keys.
74
Scenario: prefetch use case.
Prefetch detail query on likely navigation (hover/focus) for faster next screen.
75
Scenario: evaluator one-liner for cache collision.
FAIL - queryKey omits required parameters, causing cache collisions and incorrect data reuse; include all inputs and gate fetch with enabled.
76
Checklist: React Query review top 5.
1) queryKey includes all inputs 2) enabled guards missing params 3) res.ok check + throw 4) avoid mirroring data into local state 5) mutations update cache (invalidate/setQueryData)
77
Checklist: queryKey quick rules.
Namespace resources Include params (id/filters/sort) Use stable/serializable parts Avoid collisions No Dates/functions in keys
78
Checklist: async UX states.
Initial loading (isLoading) Background refetch (isFetching) Success (data) Empty state Error (alert + retry)
79
Checklist: mutation checklist.
Disable during pending Show error Invalidate/update cache Optimistic update with rollback Reconcile on settled
80
Checklist: evaluator wording for server-state issues.
Name issue (cache collision/stale data/duplicate source), impact (wrong UI/flaky UX), fix (key/enabled/invalidate/rollback).