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

Defining Actions and Reducers for WordPress Data Stores

Master the WordPress Data layer by implementing formal Actions and Reducers. Learn to manage state mutation predictably in your React-based admin dashboard.

WordPressReactReduxData LayerState Managementphpplugin-development

Previously in this course, we explored registering a custom data store and writing selectors for data access. Now that you have a store registered and a way to read data, it’s time to define how that data changes.

In the WordPress data architecture, you don't mutate state directly. Instead, you dispatch Actions—plain JavaScript objects describing what happened—which are then processed by Reducers—pure functions that determine how the state should update. This separation is the key to predictable state mutation.

The Anatomy of Actions and Reducers

Think of an action as an event notification. It contains a type (a string describing the action) and an optional payload (the data needed to perform the update).

A reducer is a function that takes the current state and an action, and returns the new state. Because reducers must be pure, they cannot modify the original state object; they must always return a new, updated version. If you've ever wrestled with React state management: Reducers vs. State Machines, you know that this functional approach is the best way to avoid side-effect bugs.

Creating Action Creators

While you could dispatch raw objects, we use Action Creators—functions that return these objects—to ensure consistency and simplify the dispatching process.

JAVASCRIPT
// store/actions.js

export function setKnowledgeBaseItems(items) {
    return {
        type: CE9178">'SET_ITEMS',
        items,
    };
}

export function updateItemStatus(id, status) {
    return {
        type: CE9178">'UPDATE_ITEM_STATUS',
        id,
        status,
    };
}

Defining Reducer Logic

Your reducer is the brain of your data store. It listens for the actions you just defined and updates the state accordingly. You should use a switch statement to handle different action types.

JAVASCRIPT
// store/reducer.js

const DEFAULT_STATE = {
    items: [],
};

export function reducer(state = DEFAULT_STATE, action) {
    switch (action.type) {
        case CE9178">'SET_ITEMS':
            return {
                ...state,
                items: action.items,
            };

        case CE9178">'UPDATE_ITEM_STATUS':
            return {
                ...state,
                items: state.items.map((item) =>
                    item.id === action.id 
                        ? { ...item, status: action.status } 
                        : item
                ),
            };

        default:
            return state;
    }
}

Notice how we use the spread operator (...state) to ensure we aren't mutating the existing state object. This follows the principles of TypeScript Immutability: Stopping Mutation Bugs in State Management by ensuring every state transition results in a new object reference.

Dispatching Actions to the Store

To trigger these updates from your React components, you use the dispatch function provided by the @wordpress/data registry.

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

const MyComponent = () => {
    const { setKnowledgeBaseItems } = useDispatch(STORE_NAME);

    const handleRefresh = async () => {
        const items = await fetchItems(); // Your service layer
        setKnowledgeBaseItems(items);
    };

    return <button onClick={handleRefresh}>Refresh Items</button>;
};

Hands-on Exercise

  1. Open your store/reducer.js file.
  2. Add a new action type REMOVE_ITEM to your reducer that filters the items array based on a provided id.
  3. Create a corresponding action creator in store/actions.js called removeItem(id).
  4. Dispatch this action from a "Delete" button in your Knowledge Base admin list component and verify that the UI updates instantly.

Common Pitfalls

  • Mutating State Directly: Never use state.items.push() or state.items[0] = value. Always return a new array or object. If you mutate, the WordPress data store won't trigger re-renders because it won't detect a change in reference.
  • Non-Serializable Payloads: Keep your action payloads simple. Avoid passing class instances or DOM nodes. Stick to plain JSON-serializable data (strings, numbers, arrays, objects).
  • Over-complicating Reducers: If your reducer logic is becoming massive, split it into smaller sub-reducers. A reducer should handle one slice of the state tree.

Recap

We've established that actions describe what happened, and reducers define how the state changes in response. By dispatching actions through the store, we ensure that our Knowledge Base plugin remains maintainable and that UI updates are strictly tied to state transitions.

Up next: Implementing Resolvers for Data Fetching.

Similar Posts