When people start learning React, they often hear: โYou need Redux!โ
But hereโs the truth: not every app needs Redux.
Redux is great, but itโs also extra code, setup, and concepts to maintain. Letโs break it down.
โ When NOT to Use Redux
If your app is small, you probably donโt need it.
Examples:
- A to-do app where only one component manages state.
- A theme toggle (dark/light mode).
- A form where values donโt need to be shared globally.
๐ In these cases, just use Reactโs built-in hooks:
// No Redux needed
import { useState } from "react";
export default function ThemeToggle() {
const [dark, setDark] = useState(false);
return (
<button onClick={() => setDark(!dark)}>
{dark ? "๐ Dark Mode" : "โ๏ธ Light Mode"}
</button>
);
}
โ When Redux is a Good Choice
Redux shines in large apps with shared state across many components.
Examples:
- An e-commerce app: cart items, user info, product filters.
- A chat app: messages, notifications, online users.
- A dashboard: global filters, real-time data, API caching.
Here, having one predictable place for state makes life much easier.
๐ Modern Redux = Redux Toolkit
If you do need Redux, donโt write boilerplate reducers/actions manually.
Use Redux Toolkit (RTK) โ the official way to write Redux today.
Example: a simple counter:
// store/counterSlice.ts
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
interface CounterState {
value: number;
}
const initialState: CounterState = { value: 0 };
const counterSlice = createSlice({
name: "counter",
initialState,
reducers: {
increment: (state) => { state.value += 1 },
decrement: (state) => { state.value -= 1 },
addBy: (state, action: PayloadAction<number>) => {
state.value += action.payload;
}
}
});
export const { increment, decrement, addBy } = counterSlice.actions;
export default counterSlice.reducer;
Hooking it up in a component:
import { useDispatch, useSelector } from "react-redux";
import { increment, decrement, addBy } from "./store/counterSlice";
export default function Counter() {
const count = useSelector((state: any) => state.counter.value);
const dispatch = useDispatch();
return (
<div>
<h2>Count: {count}</h2>
<button onClick={() => dispatch(increment())}>โ</button>
<button onClick={() => dispatch(decrement())}>โ</button>
<button onClick={() => dispatch(addBy(5))}>+5</button>
</div>
);
}
Much cleaner than old Redux boilerplate ๐
๐ก Best Practices
- Store only shared/global state in Redux.
- Keep UI state (like modals, dropdowns) in local
useState. - Use RTK Query for API data fetching & caching (built into Redux Toolkit).
- Donโt overcomplicate โ sometimes Context API is enough.
๐ Takeaway
Redux is not a must for every project.
- Small apps โ
useState/useContext. - Medium apps โ Context + hooks.
- Large apps โ Redux Toolkit for predictable state management.
๐ Remember: The right use of Redux is knowing when not to use it.
Top comments (0)