How to use wp.hooks.addAction() in React JS/Gutenberg?

I am able to successfully use wp.hooks.applyFilters() and wp.hooks.addFilter(), but I’m not able to render a React Component using wp.hooks.addAction(). However, the console.log() runs just fine within the callback for an action. This is my code:

import { createHooks } from '@wordpress/hooks';

let globalHooks = createHooks();

const Header = () => {
    return (
        <h1>Header Component</h1>
    );
}

const RevisedHeader = () => {
    return (
        <h1>Revised Header Component</h1>
    )
}

export default class App extends Component {

    constructor( props ) {
        super();

        globalHooks.addFilter( 'replace_header', 'revisedHeaderCallback', this.revisedHeaderCallback );
        globalHooks.addAction( 'after_replace_header', 'afterRevisedHeaderCallback', this.afterRevisedHeaderCallback );
    };

    revisedHeaderCallback( header ) {
        return <RevisedHeader />;
    }

    afterRevisedHeaderCallback() {
        return <RevisedHeader />;
    }

    render() {

        return(
            <div className="App">
                { globalHooks.applyFilters( 'replace_header', <Header /> ) }
                { globalHooks.doAction( 'after_replace_header' ) }
            </div>
        );
    }
}

2 Answers
2

How to use wp.hooks.addAction?

It’s basically like so, just like you’ve attempted:

// Hook to the hook_name action.
wp.hooks.addAction( 'hook_name', 'namespace', function(){
    console.log( 'Foo Bar' );
} );

// Trigger the hook_name action.
wp.hooks.doAction( 'hook_name' );

Or for hooks which provides one or more parameters to the callback:

// Hook to the hook_name action.
wp.hooks.addAction( 'hook_name', 'namespace', function( a, b ){
    console.log( a, b );
} );

// Trigger the hook_name action.
wp.hooks.doAction( 'hook_name', 'foo', [ 'bar', 'boo' ] );

I am able to successfully use wp.hooks.applyFilters() and
wp.hooks.addFilter(), but I’m not able to render a React Component
using wp.hooks.addAction().

The problem is not with your code, but it’s because unlike the wp.hooks.applyFilters function, wp.hooks.doAction simply returns nothing or it returns undefined:

  • Here an element is returned and React later rendered the element:

    { globalHooks.applyFilters( 'replace_header', <Header /> ) }
    

    The above translates to this, which renders an element:

    { <RevisedHeader /> }
    
  • Here undefined is always returned, so no elements are rendered:

    { globalHooks.doAction( 'after_replace_header' ) }
    { globalHooks.doAction( 'after_replace_header', <Header /> ) }
    

    The above translates to this, which “does nothing good”:

    { undefined }
    

So once again, the problem is that wp.hooks.doAction always returns an undefined even if for example your afterRevisedHeaderCallback function actually returns an element or component.

Hence, use globalHooks.applyFilters (or rather wp.hooks.applyFilters) if you wish to render React elements/components like so:

{ globalHooks.applyFilters( 'hook_name', <FooBar /> ) }

UPDATE

then what what purpose does doAction() serve? What would be the use
case?

To do other actions than what you’ve tried to – { globalHooks.doAction( 'after_replace_header' ) } (here you attempted to render an element or a component). So you could instead perform AJAX requests, modify an object (e.g. an Array), etc. You could also run ReactDOM.render from a callback hooked via wp.hooks.addAction, but (as you may already know) the element container has to be already attached to the DOM. But one thing for sure, wp.hooks.doAction always returns undefined.

Example for modifying an object

The callback (in your component):

afterRevisedHeaderCallback( arr ) {
    arr.push( 'bar' );
}

It’s hooked here:

globalHooks.addAction( 'after_replace_header', 'afterRevisedHeaderCallback', this.afterRevisedHeaderCallback );

Your component’s render method:

render() {
    let a = [ 'foo' ];
    globalHooks.doAction( 'after_replace_header', a );

    return(
        <div className="App">
            { globalHooks.applyFilters( 'replace_header', <Header /> ) }
            { a.join(', ') }
        </div>
    );
}

UPDATE 2

Just like in PHP in WordPress, do_action_ref_array and do_action returns nothing/NULL, but apply_filters_ref_array and apply_filters both return whatever returned by the callback to a filter/hook, which yes, could be NULL.

And if you’re skeptical about the undefined returned by wp.hooks.doAction, then check out the source here.

UPDATE 3

Based on the example in UPDATE above, you could actually render the element/component this way…

The callback (in your component):

afterRevisedHeaderCallback( arr ) {
//  arr = [ <RevisedHeader /> ]; // doesn't work
    arr[0] = <RevisedHeader />;  // works fine
}

Your component’s render method:

render() {
    let el = [ <Header /> ];
    globalHooks.doAction( 'after_replace_header', el );

    return(
        <div className="App">
            { globalHooks.applyFilters( 'replace_header', <Header /> ) }
            { el }
        </div>
    );
}

I think you could understand the trick in that approach?

Leave a Comment