Irbisa · Cheatsheet
State Management
Local vs global vs server state, Context and its re-render cost, Redux Toolkit, Zustand, Jotai, URL as state, choosing a store
What is the difference between local, global and server state in a React app?
Explain the one-way data flow in Redux. Why must reducers be pure?
Is React Context a replacement for Redux or another state manager?
Find the bug: typing in the search box re-renders every component that reads the current user.
export function AppProvider({ children }: { children: React.ReactNode }) { const [user, setUser] = useState<User | null>(null); const [query, setQuery] = useState(''); return ( <AppContext value={{ user, setUser, query, setQuery }}> {children} </AppContext> );} function Avatar() { const { user } = use(AppContext); return <img src={user?.avatarUrl} alt="" />;}What does Redux Toolkit solve compared with hand-written Redux?
import { configureStore, createSlice, type PayloadAction } from '@reduxjs/toolkit';import { useDispatch, useSelector } from 'react-redux'; const cartSlice = createSlice({ name: 'cart', initialState: { items: [] as { id: string; qty: number }[] },…Find the bug: dispatching
todosClearedruns the reducer, but the list stays on screen.const todosSlice = createSlice({ name: 'todos', initialState: { items: [] as Todo[], filter: 'all' as Filter }, reducers: { todoAdded(state, action: PayloadAction<Todo>) { state.items.push(action.payload); }, todosCleared(state) { state = { items: [], filter: state.filter }; }, },});How do
useSelectorsubscriptions work, and why can a selector cause extra re-renders?import { createSelector } from '@reduxjs/toolkit';import { useSelector } from 'react-redux'; const selectItems = (state: RootState) => state.todos.items;const selectFilter = (state: RootState) => state.todos.filter;…Where do async logic and side effects live in Redux Toolkit?
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'; export const fetchUser = createAsyncThunk('user/fetch', async (id: string, { signal }) => { const res = await fetch(`/api/users/${id}`, { signal }); if (!res.ok) throw new Error(`HTTP ${res.status}`); return (await res.json()) as User;…What is RTK Query, and when would you pick it over TanStack Query?
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'; export const api = createApi({ baseQuery: fetchBaseQuery({ baseUrl: '/api' }), tagTypes: ['Todo'], endpoints: (build) => ({…How do you store relational or list data in Redux, and what does
createEntityAdaptergive you?import { createEntityAdapter, createSlice, type PayloadAction } from '@reduxjs/toolkit'; interface Post { id: string; title: string; authorId: string; // a reference, not a nested user object…What is Zustand, and how does it differ from Redux Toolkit?
import { create } from 'zustand'; interface CartState { items: string[]; add: (id: string) => void; clear: () => void;…Find the bug: after upgrading to Zustand 5, this component crashes with "Maximum update depth exceeded".
function CartSummary() { const { items, clear } = useCart((s) => ({ items: s.items, clear: s.clear })); return ( <div> {items.length} items <button onClick={clear}>Clear</button> </div> );}What is the atomic approach to state (Jotai), and when does it fit better than one store?
import { atom, useAtom, useAtomValue } from 'jotai'; const priceAtom = atom(100);const qtyAtom = atom(1);const totalAtom = atom((get) => get(priceAtom) * get(qtyAtom)); // derived, read-only…What is MobX, and how does its observable model differ from Redux?
class CartStore { items: { id: string; price: number; qty: number }[] = []; constructor() { makeAutoObservable(this); // fields: observable, getters: computed, methods: actions }…How do you persist store state across page reloads, and what can go wrong?
import { create } from 'zustand';import { persist } from 'zustand/middleware'; type Theme = 'light' | 'dark'; interface PrefsState {…When should state live in the URL instead of in React state or a store?
Why is copying API responses into Redux or Context usually an anti-pattern, and what do you use instead?
How do you keep a store maintainable in a large app with many features and teams?
How would you migrate a large app from legacy Redux (
connect, sagas, hand-written reducers) to Redux Toolkit or TanStack Query step by step?import { configureStore } from '@reduxjs/toolkit';import createSagaMiddleware from 'redux-saga';import { legacyReducers } from './legacy/reducers'; // hand-written reducers, untouchedimport { rootSaga } from './legacy/sagas';import { cartSlice } from './features/cart/cartSlice'; // migrated to createSliceimport { api } from './services/api'; // RTK Query, filled endpoint by endpoint…When does a state machine (XState) model UI state better than booleans in a store, and what does it cost?
// flags: { isSubmitting, isError, isSuccess } allow 8 combinations, only 4 make sense type State = 'idle' | 'submitting' | 'failed' | 'succeeded';type Event = 'SUBMIT' | 'RESOLVE' | 'REJECT' | 'RESET'; // one state at a time, and each state lists the events it accepts…How would you choose a state management approach for a new React app?