Redux has been the go-to state management library for React applications, but traditional Redux requires a lot of boilerplate code. Enter Redux Toolkit—a simplified way to handle state management efficiently. One of its most powerful features is slices.
In this article, we'll break down what slices are, how they work, and how you can use them in your React app.
What is a Redux Slice?
A slice in Redux Toolkit is a self-contained piece of global state that includes:
✅ A name (to identify the slice in the store)
✅ An initial state
✅ Reducers (functions that update the state)
✅ Auto-generated actions (to trigger reducers)
Instead of manually creating action types, action creators, and reducers, Redux Toolkit does it all in one go!
Creating a Redux Slice
Let's start with a simple example: a counter slice.
1️⃣ Define the Slice
import { createSlice } from "@reduxjs/toolkit";
const counterSlice = createSlice({
name: "counter", // Name of the slice
initialState: { value: 0 }, // Initial state
reducers: {
increment: (state) => {
state.value += 1;
},
decrement: (state) => {
state.value -= 1;
},
incrementByAmount: (state, action) => {
state.value += action.payload;
},
},
});
// Export actions (auto-generated)
export const { increment, decrement, incrementByAmount } = counterSlice.actions;
// Export reducer to use in store
export default counterSlice.reducer;
2️⃣ What’s Happening Here?
- Reducers modify the state when an action is dispatched.
- Redux Toolkit automatically generates action creators with the same names as the reducers.
- We export the reducer so it can be added to the store.
Setting Up the Redux Store
To use our slice, we need to configure the Redux store.
import { configureStore } from "@reduxjs/toolkit";
import counterReducer from "./counterSlice";
const store = configureStore({
reducer: {
counter: counterReducer,
},
});
export default store;
Using Redux in a React Component
Now, let's connect Redux to a React component using useSelector and useDispatch.
import { useSelector, useDispatch } from "react-redux";
import { increment, decrement, incrementByAmount } from "./counterSlice";
export default function Counter() {
const count = useSelector((state) => state.counter.value);
const dispatch = useDispatch();
return (
<div>
<h1>Counter: {count}</h1>
<button onClick={() => dispatch(increment())}>+</button>
<button onClick={() => dispatch(decrement())}>-</button>
<button onClick={() => dispatch(incrementByAmount(5))}>+5</button>
</div>
);
}
How This Works:
-
useSelector(state => state.counter.value)
: Fetches the counter value from Redux store. -
useDispatch()
: Gets the function to dispatch actions. -
dispatch(increment())
: Calls the reducer to update the state.
Understanding Auto-Generated Actions
When we create reducers inside createSlice
, Redux Toolkit automatically generates action creators.
increment(); // { type: "counter/increment" }
decrement(); // { type: "counter/decrement" }
incrementByAmount(5); // { type: "counter/incrementByAmount", payload: 5 }
Instead of manually defining these actions like in traditional Redux, Redux Toolkit does it for us!
How This Was Done in Traditional Redux
Before Redux Toolkit, Redux required a lot more boilerplate. Here's how the same counter example would be implemented traditionally:
1️⃣ Define Action Types
const INCREMENT = "INCREMENT";
const DECREMENT = "DECREMENT";
const INCREMENT_BY_AMOUNT = "INCREMENT_BY_AMOUNT";
2️⃣ Create Action Creators
const increment = () => ({ type: INCREMENT });
const decrement = () => ({ type: DECREMENT });
const incrementByAmount = (amount) => ({ type: INCREMENT_BY_AMOUNT, payload: amount });
3️⃣ Write the Reducer
const initialState = { value: 0 };
const counterReducer = (state = initialState, action) => {
switch (action.type) {
case INCREMENT:
return { ...state, value: state.value + 1 };
case DECREMENT:
return { ...state, value: state.value - 1 };
case INCREMENT_BY_AMOUNT:
return { ...state, value: state.value + action.payload };
default:
return state;
}
};
export default counterReducer;
4️⃣ Set Up the Store
import { createStore } from "redux";
import counterReducer from "./counterReducer";
const store = createStore(counterReducer);
export default store;
5️⃣ Connect Redux to Components
import { useSelector, useDispatch } from "react-redux";
import { increment, decrement, incrementByAmount } from "./actions";
export default function Counter() {
const count = useSelector((state) => state.value);
const dispatch = useDispatch();
return (
<div>
<h1>Counter: {count}</h1>
<button onClick={() => dispatch(increment())}>+</button>
<button onClick={() => dispatch(decrement())}>-</button>
<button onClick={() => dispatch(incrementByAmount(5))}>+5</button>
</div>
);
}
🔥 Redux Toolkit vs Traditional Redux
Feature | Traditional Redux | Redux Toolkit |
---|---|---|
Boilerplate Code | High | Low |
Manual Action Types | Required | Not Needed |
Action Creators | Manually Defined | Auto-Generated |
Reducer Complexity | Uses switch-case
|
Simple function |
As you can see, Redux Toolkit reduces a lot of unnecessary code, making it easier to manage state in React applications.
Conclusion
Redux Toolkit makes state management much easier by eliminating boilerplate code. With slices, we can define our state, reducers, and actions in a clean and structured way.
Key Takeaways:
✅ Slices combine reducers and actions automatically.
✅ Auto-generated actions simplify dispatching.
✅ configureStore
makes setting up Redux effortless.
✅ React hooks (useSelector
, useDispatch
) help connect Redux with UI components.
✅ Redux Toolkit is much simpler than traditional Redux.
Now you’re ready to use Redux Toolkit in your next project! 🚀