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

Creating Custom Hooks for API Logic in WordPress Plugins

Learn how to create custom React hooks to encapsulate REST API logic. Simplify your WordPress admin components and manage shared state with cleaner code.

ReactWordPressHooksAPIJavaScriptDevelopmentphpplugin-development

Previously in this course, we explored implementing drag-and-drop sorting to enhance our Knowledge Base dashboard. While our current implementation works, the components are becoming bloated with repeated apiFetch calls, useState declarations, and useEffect lifecycle management. In this lesson, we will abstract that complexity into a custom hook.

Why Custom Hooks for API Logic?

In React, custom hooks allow you to extract component logic into reusable functions. When building WordPress admin interfaces, you often perform the same sequence of operations: fetching data, tracking a loading state, and handling errors.

Without abstraction, your components end up with "boilerplate fatigue." Every file needs its own set of useState and useEffect blocks. By moving this into a custom hook, you treat your API as a service layer that your UI consumes declaratively. This approach isn't just about cleaner code; it’s about creating a single source of truth for your data-fetching patterns.

Building the useKnowledgeBase Hook

We want a hook that returns the current items, a loading status, an error message, and a refresh function. Create a new file at src/hooks/useKnowledgeBase.js.

JAVASCRIPT
import { useState, useEffect, useCallback } from CE9178">'@wordpress/element';
import apiFetch from CE9178">'@wordpress/api-fetch';

export const useKnowledgeBase = () => {
    const [items, setItems] = useState([]);
    const [isLoading, setIsLoading] = useState(true);
    const [error, setError] = useState(null);

    const fetchData = useCallback(async () => {
        setIsLoading(true);
        try {
            const result = await apiFetch({ path: CE9178">'/kb/v1/entries' });
            setItems(result);
            setError(null);
        } catch (err) {
            setError(err.message || CE9178">'Failed to fetch Knowledge Base data.');
        } finally {
            setIsLoading(false);
        }
    }, []);

    useEffect(() => {
        fetchData();
    }, [fetchData]);

    return { items, isLoading, error, refresh: fetchData };
};

Simplifying Component Consumption

Now, look at how much cleaner your main dashboard component becomes. Instead of managing state manually, you simply call the hook.

JSX
import { useKnowledgeBase } from CE9178">'../hooks/useKnowledgeBase';
import { Spinner, Notice } from CE9178">'@wordpress/components';

const KnowledgeBaseDashboard = () => {
    const { items, isLoading, error, refresh } = useKnowledgeBase();

    if (isLoading) return <Spinner />;
    if (error) return <Notice status="error">{error}</Notice>;

    return (
        <div>
            <button onClick={refresh}>Refresh List</button>
            <ul>
                {items.map(item => <li key={item.id}>{item.title}</li>)}
            </ul>
        </div>
    );
};

This pattern effectively separates what the component displays from how the data is retrieved. If you later decide to implement caching or add authentication tokens, you only have to update the logic in useKnowledgeBase.js, not every component that displays KB entries.

Hands-on Exercise

  1. Create the hook: Save the useKnowledgeBase code provided above into your plugin's src/hooks directory.
  2. Refactor: Locate your main dashboard component (created in scaffolding the React admin dashboard).
  3. Replace: Remove all manual useState and useEffect calls used for fetching data. Replace them with the useKnowledgeBase hook.
  4. Verify: Ensure your dashboard still renders the list of items correctly after the refactor.

Common Pitfalls

  • Missing Dependency Arrays: When using useCallback or useEffect, ensure your dependency array accurately reflects the variables used. If your API call depends on a category ID, include it in the array, or the hook won't re-fetch when the ID changes.
  • Over-abstraction: Don't turn every single apiFetch call into a hook. If a component performs a unique, one-off request that isn't shared or reused, keeping the logic inside the component is perfectly acceptable.
  • State Bloat: Avoid putting too much logic in a single hook. If your hook starts managing pagination, sorting, and filtering, consider splitting it into smaller, more focused hooks like useKBPagination and useKBSorting.

Recap

We've moved from imperative, component-specific fetching to a declarative, hook-based architecture. This simplifies your codebase, makes testing easier, and ensures consistent error handling across your plugin. Custom hooks are the "glue" that keeps your React UI thin and maintainable, especially as your Knowledge Base plugin grows in complexity.

Up next: We will integrate our data layer with the WordPress block editor by building a custom block that consumes our Knowledge Base API.

Similar Posts