L4: Add Slice to Store
Register the listings slice in the Redux store
Now that we have a listings slice, let's register it in the store so Redux knows about it!
Current Store Setup
Currently, our store has an empty reducer object:
import { configureStore } from '@reduxjs/toolkit';
export const store = configureStore({
reducer: {
// Empty - no slices registered yet!
},
});What We're Building
We'll import the listings reducer and add it to the store's reducer configuration.
Step 1: Import Listings Reducer
At the top of src/state/store.js, import the listings reducer:
import { configureStore } from '@reduxjs/toolkit';
import listingsReducer from './slices/listingsSlice';
export const store = configureStore({
reducer: {
// Will add here next
},
});Note: We import the default export (the reducer), not the named exports (the actions).
Step 2: Add to Reducer Object
Add the listings reducer to the reducer configuration:
import { configureStore } from '@reduxjs/toolkit';
import listingsReducer from './slices/listingsSlice';
export const store = configureStore({
reducer: {
listings: listingsReducer,
},
});What's happening here?
Complete Code
Here's the complete updated store:
import { configureStore } from '@reduxjs/toolkit';
import listingsReducer from './slices/listingsSlice';
export const store = configureStore({
reducer: {
listings: listingsReducer,
},
});Simple and clean! Only 2 new lines to register a slice.
Verify in Redux DevTools
Let's check that our slice is registered correctly:
Open Redux DevTools
- Open your app in the browser
- Open browser DevTools (F12)
- Click the Redux tab
Check State Tab
Click the State tab. You should now see:
{
"listings": {
"items": [],
"favorites": [],
"status": "idle",
"error": null
}
}Perfect! Our listings slice is registered! 🎉
Test an Action
In the Redux DevTools Dispatch section, manually dispatch an action:
{
"type": "listings/toggleFavorite",
"payload": 123
}Click Dispatch and check the state again:
{
"listings": {
"items": [],
"favorites": [123], // ← 123 was added!
"status": "idle",
"error": null
}
}It works! Your reducer is handling actions! 🎉
Understanding State Access
Now that the slice is registered, here's how components access state:
Access entire listings slice:
import { useSelector } from 'react-redux';
function Component() {
const listings = useSelector((state) => state.listings);
console.log(listings);
// {
// items: [],
// favorites: [],
// status: 'idle',
// error: null
// }
}The useSelector hook:
- Takes a selector function:
(state) => state.listings - Returns the selected value
- Subscribes component to state changes
- Re-renders when selected state changes
Access specific fields:
import { useSelector } from 'react-redux';
function Component() {
const items = useSelector((state) => state.listings.items);
const favorites = useSelector((state) => state.listings.favorites);
const status = useSelector((state) => state.listings.status);
console.log(items); // []
console.log(favorites); // []
console.log(status); // 'idle'
}Best practice: Select only what you need!
Why?
- Component only re-renders when that specific field changes
- Better performance
- Clearer dependencies
Access multiple slices (future):
import { useSelector } from 'react-redux';
function Component() {
const listings = useSelector((state) => state.listings);
const user = useSelector((state) => state.user);
const cart = useSelector((state) => state.cart);
// Use data from multiple slices
return (
<div>
<p>User: {user.name}</p>
<p>Listings: {listings.items.length}</p>
<p>Cart: {cart.items.length} items</p>
</div>
);
}Each useSelector subscribes to one slice of state.
Common Patterns
Pattern 1: Select and Destructure
function Component() {
const { items, favorites, status } = useSelector((state) => state.listings);
return (
<div>
<p>Total: {items.length}</p>
<p>Favorites: {favorites.length}</p>
<p>Status: {status}</p>
</div>
);
}Pros:
- Clean syntax
- Easy to read
Cons:
- Re-renders when ANY field in
listingschanges - Less performant for large states
Pattern 2: Select Individual Fields
function Component() {
const items = useSelector((state) => state.listings.items);
const favorites = useSelector((state) => state.listings.favorites);
return (
<div>
<p>Total: {items.length}</p>
<p>Favorites: {favorites.length}</p>
</div>
);
}Pros:
- Only re-renders when specific fields change
- Better performance
Cons:
- More verbose
- Multiple
useSelectorcalls
Use Pattern 2 for performance-critical components!
Pattern 3: Create Selector Function
// In listingsSlice.js
export const selectListings = (state) => state.listings;
export const selectFavorites = (state) => state.listings.favorites;
export const selectIsLoading = (state) => state.listings.status === 'loading';
// In component
import { selectFavorites, selectIsLoading } from '@/state/slices/listingsSlice';
function Component() {
const favorites = useSelector(selectFavorites);
const isLoading = useSelector(selectIsLoading);
// ...
}Pros:
- Reusable selectors
- DRY principle
- Easy to test
- Can compute derived state
Recommended for real apps!
Redux State Tree
With our slice registered, the state tree looks like:
Redux Store
└─ listings (from listingsReducer)
├─ items: []
├─ favorites: []
├─ status: 'idle'
└─ error: nullAs you add more slices:
Redux Store
├─ listings (from listingsReducer)
│ ├─ items: []
│ ├─ favorites: []
│ ├─ status: 'idle'
│ └─ error: null
├─ user (from userReducer)
│ ├─ profile: null
│ └─ isAuthenticated: false
└─ cart (from cartReducer)
├─ items: []
└─ total: 0Each slice is isolated but part of the same store!
Troubleshooting
Issue: "Cannot read property 'items' of undefined"
Problem: Trying to access state before slice is registered
const items = useSelector((state) => state.listings.items);
// Error: Cannot read property 'items' of undefinedSolution: Make sure slice is added to store:
// store.js
reducer: {
listings: listingsReducer, // ← Must be here!
}Issue: "useSelector is not a function"
Problem: Not importing from 'react-redux'
import { useSelector } from 'redux'; // ❌ Wrong package!Solution: Import from 'react-redux':
import { useSelector } from 'react-redux'; // ✅ Correct!Issue: State not updating in DevTools
Problem: Not dispatching actions correctly
Solution: Make sure you're using dispatch:
import { useDispatch } from 'react-redux';
import { toggleFavorite } from '@/state/slices/listingsSlice';
function Component() {
const dispatch = useDispatch();
const handleClick = () => {
dispatch(toggleFavorite(123)); // ✅ Correct!
};
}What's Next?
Perfect! The listings slice is now registered in the store. In the next lesson, we'll:
- Create an async thunk - Fetch listings from the API
- Dispatch async actions - Call the API with Redux
- Handle loading states - Track fetch status
✅ Lesson Complete! Your listings slice is registered and visible in Redux DevTools!
Key Takeaways
- ✅ Register slices by adding them to
reducerobject - ✅ Key name determines state access:
state.listings - ✅ Import the default export (reducer function)
- ✅ Use Redux DevTools to verify registration
- ✅ Select specific fields with
useSelectorfor better performance - ✅ Create selector functions for reusable state access