WordPress Data Store Properties: Action Creator Generators

This entry is part 9 of 15 in the series, A Practical Overview of the @wordpress/data API

Now we have a resolver for asynchronously getting products via a REST api endpoint, we have some action creators, and we have a selector.  We haven’t got to the reducer yet, but before we get to it, let’s consider another problem we haven’t addressed yet. 

When we update or create a product using our ui, how are we going to persist that to the server? We could just wire up the POST/PUT endpoints directly in our component, but remember one of the reasons we’re implementing wp.data is to provide a common interface for any component needing to interact with the products data. So what can we do here?

Fortunately, we’ve covered a part of the wp.data api that provides us with a mechanism for doing this, controls. With controls, it is possible to make action creator generators that yield control action objects for handling asynchronous behaviour.  Essentially everything you’ve learned about resolver generators so far can also be applied to action creators!

So let’s go back to the action creators we’ve already prepared (reminder: src/data/products/actions.js) which are createProduct, updateProduct and deleteProduct. Right now these are not wired up to any API route. Let’s change that. If you feel adventurous, why don’t you give it a go in your own fork of the app right now and see what you come up with. You can come back and see how close you got after.

You back? Okay, here’s one approach you could end up with:

import { getResourcePath } from './utils';
import { fetch } from '../controls';
import TYPES from './action-types';

const { UPDATE, CREATE, DELETE, HYDRATE } = TYPES;

export function* createProduct(product) {
 const result = yield fetch(getResourcePath() + "/add", {
   method: "POST",
   body: product
 });
 if (result) {
   return {
     type: CREATE,
     product: result
   };
 }
 return;
}
 
export function* updateProduct(product) {
 const result = yield fetch(getResourcePath(product.id), {
   method: "PUT",
   body: product
 });
 if (result) {
   return {
     type: UPDATE,
     product
   };
 }
}
 
export function* deleteProduct(productId) {
 const result = yield fetch(getResourcePath(productId), {
   method: "DELETE"
 });
 if (result) {
   return {
     type: DELETE,
     productId
   };
 }
}

Take note of a few things here:

  • I’m using the fetch control (remember this from the post about resolvers?)
  • I’m returning the original action object that was here before the updates.

Notice that the action creator is still returning an action object, the only change here is that with controls, we’re able to do some side-effects before returning that action object.

In the next post of this series, it’s time to go on to the last property of our store registration configuration object, the reducer.

Series NavigationWordPress Data Store Properties: ResolversWordPress Data Store Properties: Reducer
  1. Hi again Darren…. In the generator actions, is it possible to still have access to the dispatch and select variables the way one does when the function is async

    export const deleteProduct = ( productId ) => async ({ select, dispatch }) => {
    // do stuff
    }

    Additionally, if you are fetching some data anyc in an action – do you still need a resolver? or if it’s going to do something based on the resolved data (for example- reading a product from the DB by ID) how can you wait for that resolution before dispatching the next action?

Leave a Reply

Up Next:

What is WordPress Data?

What is WordPress Data?