Redux Simplified - From Core Concepts to Modern Toolkit
10 Apr 2025Understanding Redux: A Beginner’s Guide to State Management
Redux is a powerful state management library that can be integrated with any UI framework, though it’s most commonly used with React. Let’s break down the core concepts and see how Redux has evolved to become more developer-friendly.
Core Redux Concepts
1. Store
The store is the central repository that holds your application’s state. Think of it as a single source of truth for your entire application’s data.
2. State
This is the actual data stored in your application. In Redux, state is immutable, meaning it cannot be directly modified.
3. Actions
Actions are plain JavaScript objects that describe what happened in your application. They always have:
- A
typeproperty (describing what kind of change is needed) - An optional
payloadproperty (containing the data for the change)
// Example action
{
type: "INCREMENT_COUNTER",
payload: 5
}
4. Reducers
Reducers are pure functions that take the current state and an action, then return a new state. They define how your state transforms in response to actions.
function counterReducer(state = 0, action) {
switch (action.type) {
case 'INCREMENT':
return state + action.payload;
case 'DECREMENT':
return state - action.payload;
default:
return state;
}
}
5. Dispatch
This is the method used to send actions to the store, triggering state updates:
store.dispatch({ type: 'INCREMENT', payload: 10 });
6. Selectors
Selectors are functions that extract specific pieces of data from the store:
const selectCount = state => state.counter.value;
React Redux
React Redux provides bindings to connect Redux with React components. It introduces:
Provider
The Provider component wraps your React application and makes the Redux store available to all components:
import { Provider } from 'react-redux';
import store from './store';
function App() {
return (
<Provider store={store}>
<YourApp />
</Provider>
);
}
Hooks for Component Integration
Before hooks, connecting components to Redux required using the connect function with mapStateToProps and mapDispatchToProps:
class Counter extends Component {
render() {
return (
<div>
<p>Count: {this.props.count}</p>
<button onClick={this.props.increment}>Increment</button>
<button onClick={this.props.decrement}>Decrement</button>
</div>
);
}
}
const mapStateToProps = (state) => ({
count: state.counter.count
});
const mapDispatchToProps = (dispatch) => ({
increment: () => dispatch(increment()),
decrement: () => dispatch(decrement())
});
export default connect(mapStateToProps, mapDispatchToProps)(Counter);
With hooks, this becomes much simpler:
import { useSelector, useDispatch } from 'react-redux';
import { increment, decrement } from './counterSlice';
function Counter() {
const count = useSelector(state => state.counter.value);
const dispatch = useDispatch();
return (
<div>
<p>Count: {count}</p>
<button onClick={() => dispatch(increment())}>Increment</button>
<button onClick={() => dispatch(decrement())}>Decrement</button>
</div>
);
}
Redux Toolkit
Redux Toolkit simplifies Redux development by reducing boilerplate code and providing helpful utilities.
CreateSlice
The createSlice function generates action creators and action types automatically:
import { createSlice } from '@reduxjs/toolkit';
export const counterSlice = createSlice({
name: 'counter',
initialState: {
value: 0,
},
reducers: {
increment: (state) => {
// Redux Toolkit uses Immer to allow "mutating" syntax
// while actually producing immutable updates
state.value += 1;
},
decrement: (state) => {
state.value -= 1;
},
incrementByAmount: (state, action) => {
state.value += action.payload;
},
},
});
// Action creators are generated automatically
export const { increment, decrement, incrementByAmount } = counterSlice.actions;
export default counterSlice.reducer;
ConfigureStore
Setting up the store is simplified with configureStore:
import { configureStore } from '@reduxjs/toolkit';
import counterReducer from '../features/counter/counterSlice';
export default configureStore({
reducer: {
counter: counterReducer,
},
});
The Redux Data Flow
- User interacts with the UI (clicks a button)
- The component dispatches an action
- The store runs the reducers with the current state and action
- Reducers create a new state based on the action
- The store notifies all connected components about the state change
- Components re-render with the new state
When to Use Redux
Redux is most beneficial when:
- Your application has complex state that’s shared across many components
- You need to track how state changes over time
- You have a medium to large-sized application with a team of developers
- You want predictable state management with clear patterns
For smaller applications, React’s built-in state management (useState, useContext) might be sufficient.
Conclusion
Redux provides a structured approach to managing state in your applications. While it has a learning curve, tools like React Redux hooks and Redux Toolkit have made it much more approachable for beginners. As your applications grow in complexity, the benefits of Redux’s predictable state container become increasingly valuable.