Main alternatives to Redux for state management:
// Example with Context API + useReducer
const initialState = { count: 0 };
const reducer = (state, action) => {
switch (action.type) {
case 'increment': return { count: state.count + 1 };
case 'decrement': return { count: state.count - 1 };
default: return state;
}
};
// Usage
const [state, dispatch] = useReducer(reducer, initialState);
dispatch({ type: 'increment' });Redux has long been the standard for state management in React applications, but today there are many alternatives that may be simpler, lighter, or better suited for specific tasks. 🔄
A built-in React solution suitable for small to medium applications:
// Create context
const CounterContext = createContext();
// Provider with useReducer
function CounterProvider({ children }) {
const [state, dispatch] = useReducer(
(state, action) => {
switch (action.type) {
case 'increment': return { count: state.count + 1 };
case 'decrement': return { count: state.count - 1 };
default: return state;
}
},
{ count: 0 }
);
return (
<CounterContext.Provider value={{ state, dispatch }}>
{children}
</CounterContext.Provider>
);
}
// Usage in component
function Counter() {
const { state, dispatch } = useContext(CounterContext);
return (
<>
Count: {state.count}
<button onClick={() => dispatch({ type: 'increment' })}>+</button>
<button onClick={() => dispatch({ type: 'decrement' })}>-</button>
</>
);
}Advantages:
Disadvantages:
A library using observable objects and reactions:
// Define state
import { makeObservable, observable, action } from 'mobx';
import { observer } from 'mobx-react-lite';
class CounterStore {
count = 0;
constructor() {
makeObservable(this, {
count: observable,
increment: action,
decrement: action
});
}
increment = () => {
this.count++;
}
decrement = () => {
this.count--;
}
}
const counterStore = new CounterStore();
// Component with observation
const Counter = observer(() => {
return (
<>
Count: {counterStore.count}
<button onClick={counterStore.increment}>+</button>
<button onClick={counterStore.decrement}>-</button>
</>
);
});Advantages:
Disadvantages:
A minimalist library with a simple hook-based API:
import create from 'zustand';
// Create store
const useCounterStore = create((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 }))
}));
// Usage in component
function Counter() {
const { count, increment, decrement } = useCounterStore();
return (
<>
Count: {count}
<button onClick={increment}>+</button>
<button onClick={decrement}>-</button>
</>
);
}Advantages:
Disadvantages:
An experimental library from Facebook for atomic state management:
import { atom, useRecoilState } from 'recoil';
// Define atom
const countAtom = atom({
key: 'countState',
default: 0
});
// Usage in component
function Counter() {
const [count, setCount] = useRecoilState(countAtom);
return (
<>
Count: {count}
<button onClick={() => setCount(count + 1)}>+</button>
<button onClick={() => setCount(count - 1)}>-</button>
</>
);
}
// Wrap application in RecoilRoot
function App() {
return (
<RecoilRoot>
<Counter />
</RecoilRoot>
);
}Advantages:
Disadvantages:
A primitive atomic library inspired by Recoil:
import { atom, useAtom } from 'jotai';
// Create atom
const countAtom = atom(0);
// Derived atoms
const doubleCountAtom = atom(
(get) => get(countAtom) * 2
);
// Usage in component
function Counter() {
const [count, setCount] = useAtom(countAtom);
const [doubleCount] = useAtom(doubleCountAtom);
return (
<>
Count: {count} (Double: {doubleCount})
<button onClick={() => setCount(count + 1)}>+</button>
<button onClick={() => setCount(count - 1)}>-</button>
</>
);
}Advantages:
Disadvantages:
A library for state management based on finite state machines:
import { createMachine, assign } from 'xstate';
import { useMachine } from '@xstate/react';
// Define state machine
const counterMachine = createMachine({
id: 'counter',
initial: 'active',
context: { count: 0 },
states: {
active: {
on: {
INCREMENT: {
actions: assign({ count: (ctx) => ctx.count + 1 })
},
DECREMENT: {
actions: assign({ count: (ctx) => ctx.count - 1 })
}
}
}
}
});
// Usage in component
function Counter() {
const [state, send] = useMachine(counterMachine);
return (
<>
Count: {state.context.count}
<button onClick={() => send('INCREMENT')}>+</button>
<button onClick={() => send('DECREMENT')}>-</button>
</>
);
}Advantages:
Disadvantages:
A proxy-oriented library for state management:
import { proxy, useSnapshot } from 'valtio';
// Create proxy state
const state = proxy({ count: 0 });
// State mutations
const actions = {
increment: () => { state.count++ },
decrement: () => { state.count-- }
};
// Usage in component
function Counter() {
const snap = useSnapshot(state);
return (
<>
Count: {snap.count}
<button onClick={actions.increment}>+</button>
<button onClick={actions.decrement}>-</button>
</>
);
}Advantages:
Disadvantages:
A specialized library for server state management:
import { useQuery, useMutation, QueryClient, QueryClientProvider } from 'react-query';
// Setup client
const queryClient = new QueryClient();
// Component with queries
function TodoList() {
// Fetch data
const { data: todos } = useQuery('todos', fetchTodos);
// Mutate data
const mutation = useMutation(addTodo, {
onSuccess: () => {
queryClient.invalidateQueries('todos');
}
});
return (
<>
<ul>
{todos?.map(todo => <li key={todo.id}>{todo.title}</li>)}
</ul>
<button onClick={() => mutation.mutate({ title: 'New Todo' })}>
Add Todo
</button>
</>
);
}
// Wrap application
function App() {
return (
<QueryClientProvider client={queryClient}>
<TodoList />
</QueryClientProvider>
);
}Advantages:
Disadvantages:
| Library | Size | Complexity | Performance | Ecosystem |
|---|---|---|---|---|
| Redux | Medium | High | Good | Extensive |
| Context | 0KB | Low | Medium | Built-in |
| MobX | Small | Medium | Excellent | Good |
| Zustand | Small | Low | Good | Growing |
| Recoil | Medium | Medium | Good | Growing |
| Jotai | Small | Low | Good | New |
| XState | Medium | High | Good | Growing |
| Valtio | Small | Low | Excellent | New |
| React Query | Medium | Medium | Excellent | Good |
Modern Redux alternatives offer simpler and more specialized solutions for state management:
The choice depends on project size, performance requirements, and team preferences. 🎯