Gutenberg: Is withAPIData being deprecated?

Created on 20 Jun 2018  路  11Comments  路  Source: WordPress/gutenberg

I've seen some mentions here about withAPIData being deprecated in the near future. I'm using this component in a couple of blocks I'm developing and I don't know which is the alternative method to get dynamic data. I see that the Latest Posts block is still using it, so I don't know how to proceed.

Would someone point me to the right direction, please?

Thanks

[Feature] Extensibility [Type] Question

Most helpful comment

@phpbits I had the problem with the _"Uncaught (in promise) Error: Actions must be plain objects."_ warning and found a solution to that. It seems that the resolver methods no longer retrieve the state.

So in the example on this page, this code

resolvers: {
* getPrice( state, item ) {
    const path = '/wp/v2/prices/' + item;
    const price = yield actions.fetchFromAPI( path );
    return actions.setPrice( item, price );
  },
}

need to be changed to this:

resolvers: {
* getPrice( item ) {
    const path = '/wp/v2/prices/' + item;
    const price = yield actions.fetchFromAPI( path );
    return actions.setPrice( item, price );
  },
}

Plus: If you're using an old example, please note that you no need a control method in your store. The page that I've linked says that _"This can be particularly useful in implementing asynchronous data flows"_

Hope this helps you as well.

All 11 comments

Yes, correct. We are planning to deprecate it soon.

It's not marked as deprecated yet, because we still use it in a few places, but it's something we want to replace with data module. An alternative approach would be to use withSelect to fetch data like in the Categories block:
https://github.com/WordPress/gutenberg/blob/c2a5189baf51d617b7e0763a047b5c8f482b73df/core-blocks/categories/edit.js#L210-L217

getCategories has also a corresponding resolver which triggers network requests and ensures that the data store is updated with the response data which comes from the server:
https://github.com/WordPress/gutenberg/blob/5851831090da2030181af8dd9aa96da1e29b9331/packages/core-data/src/resolvers.js#L26-L29

In addition, we offer a selector which verifies if the request is in progress:
https://github.com/WordPress/gutenberg/blob/4d3e3f6a354be40434d8f09bca696b09afeed9c7/packages/core-data/src/selectors.js#L74-L76

Related docs:

It might be a good idea to update the handbook section dedicated to building dynamic blocks cause it still makes reference to withAPIData:

https://wordpress.org/gutenberg/handbook/blocks/creating-dynamic-blocks/

Good catch, I opened #7397. Thanks!

I don't know if this is the right place to comment but I'm experiencing a malfunction of the code with withSelect that is now proposed in the documentation here
. An older version with withAPIData works without errors, I don't know exactly why.

Hi there, I also don't know if this is the correct place to comment, but following the new guidance I cannot get withSelect to work where I previously used withAPIData. I am trying to setup a custom API endpoint for the call.

My issue is that the 'controls' section of the recomended registerStore never fires. In the documentation it says that this is an opt-in component, and I need to enable it via the use command, however this is undefined by default in v3.5.0 so I have to import it via @wordpress/data, this however then gives me lodash conflicts.

Even after all that, I'm not sure if I am going down the right path. withAPIData was pretty simple for me to understand, but I must admit I'm a little lost now.

For some more examples of my specific issue, I've wrote about my problem on stackexchange here: https://wordpress.stackexchange.com/questions/311431/in-gutenberg-now-that-withapidata-is-being-deprecated-how-can-i-do-an-async-ca if its of any help.

@IacopoC I've now answered my own question, it may help you too: https://wordpress.stackexchange.com/a/311551/148566

Here is my solution:

const { apiFetch }          = wp;
const {
    registerStore,
    withSelect,
} = wp.data;

const actions = {
    setUserRoles( userRoles ) {
        return {
            type: 'SET_USER_ROLES',
            userRoles,
        };
    },

    receiveUserRoles( path ) {
        return {
            type: 'RECEIVE_USER_ROLES',
            path,
        };
    },
};

const store = registerStore( 'matt-watson/secure-block', {
    reducer( state = { userRoles: {} }, action ) {

        switch ( action.type ) {
            case 'SET_USER_ROLES':
                return {
                    ...state,
                    userRoles: action.userRoles,
                };
            case 'RECEIVE_USER_ROLES':
                return action.userRoles;
        }

        return state;
    },

    actions,

    selectors: {
        receiveUserRoles( state ) {
            const { userRoles } = state;
            return userRoles;
        },
    },

    resolvers: {
        * receiveUserRoles( state ) {
            const userRoles = apiFetch( { path: '/matt-watson/secure-blocks/v1/user-roles/' } )
                .then( userRoles => {
                    return actions.setUserRoles( userRoles );
                } )
            yield userRoles;
        },
    },

} );

By doing this you can access this via withSelect like so:

edit: withSelect( ( select ) => {
                return {
                    roles: select('matt-watson/secure-block').receiveUserRoles(),
                };
            } )( props => {

@mwtsn Thank you

@mattwatsoncodes @gziolo The latest dev version is returning the error below :

Uncaught (in promise) Error: Actions must be plain objects. Use custom middleware for async actions.

Hoping you can point me out on the best solution. Thanks!

For those stumbling on this in search be aware that this pull has examples that will no longer work because of api changes in the wp.data package. More up-to-date examples and current documentation can be found here: https://github.com/WordPress/gutenberg/tree/master/packages/data

@phpbits I had the problem with the _"Uncaught (in promise) Error: Actions must be plain objects."_ warning and found a solution to that. It seems that the resolver methods no longer retrieve the state.

So in the example on this page, this code

resolvers: {
* getPrice( state, item ) {
    const path = '/wp/v2/prices/' + item;
    const price = yield actions.fetchFromAPI( path );
    return actions.setPrice( item, price );
  },
}

need to be changed to this:

resolvers: {
* getPrice( item ) {
    const path = '/wp/v2/prices/' + item;
    const price = yield actions.fetchFromAPI( path );
    return actions.setPrice( item, price );
  },
}

Plus: If you're using an old example, please note that you no need a control method in your store. The page that I've linked says that _"This can be particularly useful in implementing asynchronous data flows"_

Hope this helps you as well.

Thanks @phpbits @nerrad @code-flow the updated code for my solution is as follows:

const actions = {
    setUserRoles( userRoles ) {
        return {
            type: 'SET_USER_ROLES',
            userRoles,
        };
    },
    receiveUserRoles( path ) {
        return {
            type: 'RECEIVE_USER_ROLES',
            path,
        };
    },
};

const store = registerStore( 'matt-watson/secure-block', {
    reducer( state = { userRoles: {} }, action ) {

        switch ( action.type ) {
            case 'SET_USER_ROLES':
                return {
                    ...state,
                    userRoles: action.userRoles,
                };
        }

        return state;
    },

    actions,

    selectors: {
        receiveUserRoles( state ) {
            const { userRoles } = state;
            return userRoles;
        },
    },

    controls: {
        RECEIVE_USER_ROLES( action ) {
            return apiFetch( { path: action.path } );
        },
    },

    resolvers: {
        * receiveUserRoles( state ) {
            const userRoles = yield actions.receiveUserRoles( '/matt-watson/secure-blocks/v1/user-roles/' );
            return actions.setUserRoles( userRoles );
        },
    },
} );
Was this page helpful?
0 / 5 - 0 ratings