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

Performance Optimization with Selectors in WordPress React Apps

Master React Performance Optimization in WordPress. Learn how to implement shallow comparison and memoized selectors to prevent unnecessary re-renders.

WordPressReactPerformanceOptimizationSelectorsphpplugin-development

Previously in this course, we covered writing selectors for data access to retrieve state from our custom data store. While those basic selectors work for simple data, they can trigger expensive re-renders in your admin dashboard if they return new object references every time they are called. Today, we’re leveling up: we will learn to optimize selector performance to ensure our Knowledge Base plugin remains responsive as our dataset grows.

The Problem: Why Selectors Cause Re-renders

In the WordPress Data module, a component subscribed to a selector will re-render whenever the value returned by that selector changes. This check is performed using a "shallow equality" comparison. If your selector returns a new object or array—even if the underlying data inside is identical—React assumes the state has changed and forces a re-render.

This is a classic performance trap. If your Knowledge Base dashboard has a list of 50 articles and your selector returns a fresh array object every time, every single list item component will re-render on every state update, even if the data for that specific item hasn't changed.

Implementing Shallow Comparison and Memoization

To prevent these unnecessary updates, we must ensure our selectors return the exact same reference if the input state hasn't changed. We do this using createSelector from the @wordpress/data package, which provides memoization by default.

Consider this unoptimized selector:

JAVASCRIPT
// A common performance pitfall
const getActiveArticles = (state) => {
    return state.articles.filter(article => article.status === CE9178">'publish');
};

Every time getActiveArticles is called, .filter() creates a new array instance. If you use this in a component via useSelect, that component will re-render every time any part of the global state changes, because the array reference is always "new."

Here is how we optimize it:

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

const getActiveArticles = createSelector(
    (state) => {
        return state.articles.filter(article => article.status === CE9178">'publish');
    },
    (state) => [state.articles] // Dependency array
);

The createSelector function takes two arguments: the transformation function and a dependency function. It only re-runs the transformation if the result of the dependency function changes. By returning [state.articles], we tell the store: "Only re-calculate the filtered list if the articles array reference itself changes."

Hands-on Exercise: Optimizing the Knowledge Base List

Let's apply this to our Knowledge Base plugin. Open your store/selectors.js file and find your article list selector.

  1. Refactor: Wrap your existing selector in createSelector.
  2. Define Dependencies: Identify exactly which part of the state tree your selector depends on.
  3. Verify: Use the React Developer Tools "Profiler" tab to record your dashboard interactions. Look for the "Why did this render?" badge. If you see "Props changed" for your list items, your selector is likely returning new references.

Common Pitfalls

  • Over-memoization: Don't wrap every trivial selector in createSelector. Memoization consumes memory. Only optimize selectors that return derived objects or arrays, or those that perform expensive computations.
  • Ignoring Dependency Arrays: If you pass an incorrect dependency (e.g., watching the wrong state slice), your UI will become stale and fail to update when data actually changes.
  • Anonymous Functions in Selectors: If you define the transformation function inline inside createSelector, make sure you aren't creating new function references that break the memoization cache.

Profiling Your Dashboard

To see these optimizations in action, you need to measure them. In your browser's DevTools:

  1. Open the Profiler tab.
  2. Click the "Record" button.
  3. Perform an action in your Knowledge Base dashboard (e.g., adding an article).
  4. Stop recording and inspect the "Ranked" chart.

If you see a component rendering that shouldn't be, check the selector it's using. If it's returning a fresh object, you've found your performance bottleneck. This is a critical step to take alongside understanding React re-rendering, as it ensures your plugin handles data-heavy admin interfaces with ease.

By mastering these techniques, you ensure that your WordPress plugins provide a professional, lag-free experience for site administrators. This is a core pillar of structuring state for performance in larger React applications.

Up next: We will tackle complex state dependencies where one selector needs to consume the output of another, ensuring our data remains consistent across the entire dashboard.

Similar Posts