How to Implement Redux Selectors in React
This article provides a practical guide on how to implement Redux
selectors in a React application to query and derive state efficiently.
You will learn how to create basic selectors, integrate them with the
useSelector hook, and use the Redux Toolkit’s
createSelector utility to build memoized selectors that
optimize your application’s performance.
What is a Redux Selector?
A selector is a pure function that takes the Redux state as an argument and returns a specific slice of that state, or derives new data from it. Selectors encapsulate the structure of your state, meaning that if you change the shape of your Redux store in the future, you only need to update the selector rather than every component that queries that data.
Step 1: Writing Basic Selectors
Basic selectors simply retrieve raw data directly from the Redux store. They are typically defined alongside your Redux slices.
// features/cart/cartSlice.js
// Example state structure: { cart: { items: [...], discount: 0.1 } }
export const selectCartItems = (state) => state.cart.items;
export const selectDiscount = (state) => state.cart.discount;Step 2: Using Selectors in React Components
To use these selectors inside your React components, import the
useSelector hook from react-redux and pass the
selector function to it.
// components/Cart.jsx
import React from 'react';
import { useSelector } from 'react-redux';
import { selectCartItems } from '../features/cart/cartSlice';
export const Cart = () => {
const items = useSelector(selectCartItems);
return (
<div>
<h2>Your Cart</h2>
<ul>
{items.map((item) => (
<li key={item.id}>{item.name} - ${item.price}</li>
))}
</ul>
</div>
);
};Step 3: Implementing Memoized Selectors with Reselect
When you need to compute derived data (such as filtering a list or calculating a total price), a basic selector will recalculate on every render. To prevent unnecessary recalculations and re-renders, you should use memoized selectors.
Redux Toolkit includes the createSelector function from
the Reselect library for this purpose.
// features/cart/cartSlice.js
import { createSelector } from '@reduxjs/toolkit';
// Input selectors (basic selectors)
export const selectCartItems = (state) => state.cart.items;
export const selectDiscount = (state) => state.cart.discount;
// Memoized selector
export const selectCartSubtotal = createSelector(
[selectCartItems],
(items) => items.reduce((total, item) => total + item.price, 0)
);
// Memoized selector that depends on other selectors
export const selectCartTotalWithDiscount = createSelector(
[selectCartSubtotal, selectDiscount],
(subtotal, discount) => subtotal * (1 - discount)
);How Memoization Works
The createSelector function accepts an array of input
selectors and an output combiner function.
- It runs the input selectors and grabs their results.
- If the results of the input selectors have not changed since the
last run (using strict
===equality reference checks), it skips running the output function and returns the cached result. - If any input value has changed, it executes the output function with the new values, caches the new result, and returns it.
Step 4: Using Memoized Selectors in Components
You consume memoized selectors in your components using the exact same syntax as basic selectors.
// components/OrderSummary.jsx
import React from 'react';
import { useSelector } from 'react-redux';
import { selectCartTotalWithDiscount } from '../features/cart/cartSlice';
export const OrderSummary = () => {
const total = useSelector(selectCartTotalWithDiscount);
return (
<div className="summary">
<h3>Total Amount Due: ${total.toFixed(2)}</h3>
</div>
);
};