Back to Blog
Lesson 19 of the Intermediate WordPress Plugins: REST API & React Admin course
WordPressJune 25, 20263 min read

Writing Selectors for Data Access: Memoization in WordPress

Master selectors in @wordpress/data to efficiently retrieve state. Learn to implement memoization for high-performance React admin interfaces in WordPress.

WordPressReact@wordpress/dataSelectorsMemoizationphpplugin-development

Previously in this course, we explored registering a custom data store in WordPress, which set the foundation for managing our plugin's state. In this lesson, we move from defining the store to extracting data from it, ensuring our components only re-render when the specific data they depend on actually changes.

The Role of Selectors in @wordpress/data

In the WordPress data store architecture, selectors are pure functions that take the state as an argument and return a specific slice of data.

Directly accessing the store state inside a component is an anti-pattern. If you access a large object directly, your component will re-render whenever any part of that object changes, even if the specific property you care about remains identical. Selectors solve this by acting as a bridge, transforming raw state into the exact format your UI needs.

Implementing Memoization

Because selectors run every time the store changes, they must be performant. We use memoization to cache the result of a selector based on its arguments. If the arguments haven't changed, the selector returns the cached result instead of re-calculating it.

In the WordPress data ecosystem, we typically use createSelector from the @wordpress/data package, which is built on top of the popular reselect library.

Worked Example: Retrieving Knowledge Base Items

Let's assume our Knowledge Base store holds an array of items. We want a selector that filters these items by a specific category.

JAVASCRIPT
import { createSelector } from CE9178">'@wordpress/data';

// The base selector: returns the raw items from state
export const getKnowledgeBaseItems = (state) => {
    return state.items;
};

// The memoized selector: filters items by category
export const getItemsByCategory = createSelector(
    (state, category) => {
        const items = getKnowledgeBaseItems(state);
        return items.filter((item) => item.category === category);
    },
    (state, category) => [state.items, category] // Dependency array
);

In this example, createSelector accepts two arguments:

  1. The result function: The logic that computes the derived data.
  2. The dependency function: A function that returns an array of dependencies. If these dependencies match the previous run, the result function is skipped.

Querying Store State from Components

To use these selectors inside your React components, you use the useSelect hook. This hook automatically subscribes the component to the store and triggers a re-render when the selector's output changes.

JAVASCRIPT
import { useSelect } from CE9178">'@wordpress/data';
import { STORE_NAME } from CE9178">'./store';

const CategoryList = ({ category }) => {
    const items = useSelect((select) => {
        return select(STORE_NAME).getItemsByCategory(category);
    }, [category]);

    if (!items.length) return <p>No items found.</p>;

    return (
        <ul>
            {items.map(item => <li key={item.id}>{item.title}</li>)}
        </ul>
    );
};

Hands-on Exercise

  1. Open your Knowledge Base store definition file.
  2. Implement a getArchivedItems selector that returns only items where status === 'archived'.
  3. Use createSelector to ensure this filtering logic is memoized.
  4. Update your Dashboard component to use useSelect and display a count of archived items in a header summary.

Common Pitfalls

  • Violating Purity: Selectors must remain pure. Never perform side effects (like API calls or console.log with mutations) inside a selector. If you need to fetch data, use resolvers.
  • Over-selecting: Avoid creating one giant selector that returns the entire state object. Create granular selectors that return only what a specific component requires.
  • Dependency Array Mismatch: If you forget to include a variable used in your selector logic within the dependency array of createSelector, the selector will return stale data.
  • Ignoring useSelect: Manually subscribing to the store using subscribe is error-prone and inefficient. Always prefer useSelect.

Selectors are the primary way your UI communicates with your data. By keeping them pure and memoized, you ensure that your admin dashboard remains responsive even as your Knowledge Base grows.

Up next: Defining Actions and Reducers to modify the store state.

Similar Posts