WordPress Data Interlude: Let’s talk Apps

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

In the last post I gave you a quick overview of the api for registering a new data store. I mentioned that this next post would take a closer look at the individual properties of a store, but before we do that, let’s take a brief break and take a look at an app that we’ll use to illustrate and practice the various concepts and apis around wp.data. The app we’re going to work with does the following:

  • A view that displays products in a product directory. Each product has an add to cart button for adding the product to a cart.
  • A view that displays the contents of the cart, the total for the items the cart, and a way to remove items from the cart.
  • A view for adding, editing and deleting existing products (it might serve as the admin view eventually).

So, go ahead and play around with this app I’ll be here when you get back.

You back? Great! The code portion of the app is here. Go ahead and take a few minutes to look at the code.

Now that you’ve taken a look at the code, let’s think about the design of the app for a few minutes. 

Read more “WordPress Data Interlude: Let’s talk Apps”

WordPress Data: How to Register a Custom Store

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

The primary way in which you interact with state in wp.data is through a registered store. In this post we’re going to give an overview of the api for registering a store and then subsequent posts will dive into the specific components of the store config.

registerStore( reducerKey, options )

Every data store found in wp.data has to be registered and you can see many examples of this throughout the Gutenberg codebase. The interface via which you register a store with wp.data is via the registerStore function. Through this function you add your store to the centralized data registry.

Sidenote: Something important to mention here is that when you register a store through wp.data.registerStore, you are registering with the default registry. This has some implications that we’ll get into a later article. In nearly all cases, it’s okay to register with the default store.

The registerStore function accepts two arguments: a name to identify the module (or store), and an object with values describing  how your state is represented, mutated (or modified), and accessed. 

The first argument can be referred to by many different terms, “store namespace”, “store key”, “store name”, “module name”, “module namespace”, or even “reducer key”! To keep things simple, we’ll call this argument the store name. It must be unique and a common pattern for naming data stores is to do something like group/store_content.  The group portion of the store name here might be your plugin name, or application name etc. The store_content portion of the store name here might be what kind of data is kept in the store.

Read more “WordPress Data: How to Register a Custom Store”

WordPress Data: Interfacing With the Store

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

Now that we have our new custom data store registered, we need to start integrating it with our example app. There are numerous ways in which you can interface with the data store in your components but I’m going to cover the four most common, straightforward ways.

withSelect( mapToProps )( Component)

withSelect is a higher order component that you use to connect your custom wp.data store with a component.

The argument you feed the curried function is a callback that maps values from selected state in wp.data to props that will then be fed through to the wrapped component. This callback you provide will receive two arguments: the first is select which is an interface to the wp.data registered stores, and ownProps which is the props that are passed into the component from parent components in the tree.

Here’s an example of withSelect being used:

Read more “WordPress Data: Interfacing With the Store”

WordPress Data: Putting it all together and registering your store!

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

To recap: so far in the series we’ve looked at the various properties of the configuration object for a store:

  • selectors: which interface with the store for retrieving data from its state.
  • actions: (actually action creators) which are used to dispatch action objects for handling by the reducer.
  • reducer: which receives dispatched actions and determines what happens to the state as a result.
  • controls: allowing for asynchronous side-effects on action generators or resolvers.
  • resolvers: linked to selectors, resolvers allow for automatically resolving data for the initial slice of state the selector is retrieving for.

Read more “WordPress Data: Putting it all together and registering your store!”

WordPress Data Store Properties: Controls

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

Often with any sort of state in a given application, there can be times in an application’s lifecycle where you want to be able to execute some sort of logic as a part of the flow in setting state or updating state. A good example of this is asynchronous data flows between the client and server sides of your application (eg. persisting state to a server database via a REST API request).

In wp.data, a control (or control function) defines the execution flow behavior associated with a specific action type. You can then use the control action creators in store action creators, and resolvers, and you can register defined controls to handle this execution as instructed within your store.

Let’s take a look at an example control action and corresponding control function found in the src/data/controls.js file within the example app:

export const fetch = (path, options = {}) => {
  if (options.body) {
    options.body = JSON.stringify(options.body);
    options.headers = { "Content-Type": "application/json" };
  }
  return {
    type: "FETCH",
    path,
    options
  };
};

export default {
  FETCH({ path, options }) {
    return new Promise((resolve, reject) => {
      window
        .fetch(path, options)
        .then(response => response.json())
        .then(result => resolve(result))
        .catch(error => reject(error));
    });
  }
};

At the top of the file is the fetch control action creator which receives the same argument shape as the window.fetch function and then returns a control action object that has FETCH as the action type, and passes along the path and options property and values.

Then we are exporting a default object that is our control object that has all the defined control functions. In this object is a FETCH property that has a function as a callback, this function is the control function that will get invoked when the control action with the FETCH type is returned or yielded from an action creator or a resolver.

This default object is what would get registered to your store as the value for the controls object. Let’s go over a few rules of this object:

  • Each property is the same value as the control action type you want the defined control function to react to.
  • The value attached to each property is a control function which receives the original action object associated with the control action type.
  • The control function should return ether a Promise or any other value.

In this series, we will have opportunity to implement controls in the example application, however to help with visualizing how controls are implemented, here’s a quick look at an example store action creator that has been updated to be a store action creator generator implementing controls:

import { fetch } from './controls';

export function* updateAndPersistThing = ( thing ) => {
    // catch any request errors.
    try {
        // execution will pause here until the `FETCH` control function's return
        // value has resolved.
        const updatedThing = yield fetch( 
            'https://thingupdaterapi.com/things',
            { method: 'PUT', data: thing }
        );
    } catch( error ) {
        // returning an action object that will save the update error to the state.
        return { type: 'THING_UPDATE_ERROR', message: error.message };
    }
    if ( updatedThing ) {
        // thing was successfully updated so return the action object that will
        // update the saved thing in the state.
        return { type: 'UPDATE_THING', thing }
    }
    // if execution arrives here, then thing didn't update in the state so return 
    // action object that will add an error to the state about this.
    return { type: 'THING_UPDATE_ERROR', message: 'Thing did not get updated.' }
}

You implement control action creators in either action creators or resolvers that are defined as generators which yield action types. When wp.data encounters an action creator (or resolver) as a generator as a part of the execution flow, under the hood it steps through each yielded value and for controls that return a promise, it will await the resolution of the promise and return that as the value of the yield assignment.  If the control handler returns undefined, the execution is not continued.

Sidenote: Generators are a whole subject on their own that is good to have an understanding of to fully comprehend how wp.data is using them. A good resource for understanding generators is this MDN article or this post.

Controls can be one of the harder interfaces of wp.data to understand, yet once you do, there is immediate benefit in having a clearer flow of execution for actions and resolvers having side-effects.

The good news, is there is a package available that exposes three commonly used controls for usage in your stores,@wordpress/data-controls. The controls exposed in this package will cover most of the use-cases you might have for controls in a custom data store, in a WordPress environment. The controls exposed by this package are:

apiFetch

This control action creator will yield an action type that triggers a control function for performing an api fetch call using the object provided to the action creator. Essentially it uses the @wordpress/api-fetch interface, but wrapped in a control for usage in wp.data action creator and resolver generators.

It should be noted that this implementation is currently coupled to interacting with the WordPress REST api (PUT, and DELETE methods are sent on the request as a header instead of as the request type and the service we’re using doesn’t know about the header). Thus for the example application used in this series, I’ve created a custom control that implements window.fetch directly. This is the example referenced at the beginning of this article.

dispatch

This control action creator will yield an action type that can be used to dispatch another action in a different store within the same data registry.

select

This control action creator will yield an action type that can be used to select data from the state in another store within the same data registry. 

Note: this control will automatically detect if the selector is attached to a resolver and will wait for the resolution to finish before returning the value of the selector. We haven’t addressed resolvers yet in this series, but don’t worry, we’re going to jump into that in the next post!

The best way to understand the usage of controls is to, well, use them. So in the next post we’ll jump back to learning about the resolvers property in the registerStore configuration object.

WordPress Data Store Properties: Selectors

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

The job of selectors is to provide an interface to access state from the registered data store. With wp.data this is the primary way that your store state is exposed and allows you to encapsulate logic surrounding exposing that data. For instance, let’s say you just want to store all products in the store state as a simple array of product objects:

const state = [
    { id: 1, name: 'Scarf', price: '1025' },
    { id: 5, name: 'Hat', price: '356' },
];

You could create a selector that returns the entire state and then any components wanting just a specific product could filter that state:

export const ProductName = ( { productID } ) => {
    const products = useSelect( ( select ) => select('mystore').getAllProducts(), [] );
    //get just the product we want to use.
    const product = products.filter( ( product ) => product.id === productID );
    return <h1>{ product.name }</h1>
};

Sidenote: In the above example useSelect is something you might not know about yet. I will cover this later in the series but for now, it’s sufficient to understand that getAllProducts is the selector being called here.

In the example, we have a getAllProducts selector that is returning all the products stored from the store state and then the component is taking care of filtering that to just the product needed. However, I can do better, if we move the filtering logic into a selector:

export const ProductName = ( { productId } ) => {
    const product = useSelect( ( select ) => select( 'mystore' ).getProduct( productId ), [ productId ] );
    return <h1>{ product.name }</h1>;
};

Now instead of having to do the same filtering logic in every component where I need a single product from the store state, I can just use the getProduct selector.

Sidenote: I usually avoid getting too granular with the created selectors initially to avoid over-engineering and creating selectors that might never be needed. So even with the example above, I probably would have just started with a getProducts selector first and then only add the more granular getProduct selector if I saw a repeated pattern in my components of getting a single product out from the array of products.

So selectors are basically your window into retrieving what slice of state you need from the store. With that in mind, let’s dive into creating our selectors in our app. First, here’s the rough shape of what selectors look like:

export const someSelector = ( state, name ) => {
    return state[ name ];
};

Let’s break this down:

  • the selector is a function (preferably pure).
  • every selector receives the current state as the first argument.
  • you can define an arbitrary number of arguments the selector receives depending on your needs. In this example, our state is an object and I’ve indicated the first argument is a name used to return a specific property value from the state object.
  • the selector returns a value from the state using the arguments provided.

Sidenote: When the wp.data api calls your defined selector, it will automatically inject and pass along the current state as the first argument along with any other arguments the selector is invoked with. So even though you define your selectors with state as the first argument, you will call your selectors without the state argument (you’ll actually be calling a created function created by the wp.data api that maps to your selector).

With this in mind then, going to our app, what is one selector you know we’ll need for sure to interface with the state?

Something to retrieve the products right? So let’s create a selector that gets the products from the store state. We’ll create a file for holding our selector called selectors.js. You should now have the following folder structure in your app: src/data/products/selectors.js. If it isn’t already, go ahead and open up the selectors.js file. Go ahead and give a go at creating your selector and come back when you’re done (don’t cheat and read ahead! Try to see how well you understand the concepts so far first).

All done? If I’ve done a good job explaining selectors so far in this, and you have the same idea of what shape the state will be in our store as I do, then in this file, you’ll probably have at least something like this (might not be exactly the same, but generally the same thing):

export const getProducts = ( state ) => state.products || [];

Let’s break this down. I decided that I’m going to store products in the state in a property called products (how original!). I also indicated what will be returned if the products property isn’t defined yet (or is non-truthy) in the state. I like returning the same data type as what I expect to store things in so here, I’m returning an empty array. From this you can infer that we plan to store products in the state as an array.

Sidenote: Why am I storing products as a property on the state instead of just on the root object as an array of product objects? I tend to follow this pattern for the state shape in created stores to avoid painting myself in a corner in future iterations where I might want to keep additional data in the state. This often limits any refactoring I might have to do down the road.

Now that we have our selector in place for our app, we likely are going to initially retrieve the products from somewhere (via an REST request) right? Something unique to wp.data that helps with this is a thing called resolvers.  But before we jump into the world of resolvers, we need to first learn a little bit about the controls property. This will be the next post in the series.

WordPress Data Series Overview and Introduction

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

For the past couple of years, my involvement with the Gutenberg project in WordPress has frequently taken me into the innards of @wordpress/data.  I’ve had to use it for projects integrating with the new WordPress Block Editor (Gutenberg), new interfaces and user experiences utilizing the new WordPress JavaScript packages, and I’ve also been directly involved with various improvements via contributions to the package itself.

In that time, I’ve had the opportunity to learn quite a bit about this package and the promise it holds for data and state management in the WordPress future and at the same time I’ve also observed the apparent scarcity of really exhaustive and thorough documentation about it.  This has surfaced multiple times as I’ve interacted with teammates or various WordPress developers who have various questions about how to use it. 

So, this series of posts is something I’ve been working on for a while that I hope will help close the gap for more people on understanding what @wordpress/data is and how to use it. Since there’s a lot of material to cover, I’m splitting this series up into smaller chunks and publishing each post in the series over time. 

Read more “WordPress Data Series Overview and Introduction”

Into the next decade…

It’s been a while since I’ve written one of these year end, year beginning posts, but this is a significant year as the 2010’s draw to a close and the 2020’s have begun. So I figured it be a good exercise to reflect and predict. Let’s start with reflect:

Reflect

I’m going to group things by Personal, Career, and General. Personal will be things that have happened in my family, and life more close to home. Career will be things that have happened in my work life. General is just general observations about the world as a whole.

Read more “Into the next decade…”

Fantastic hooks and where to use them.

This post is an introduction to the useDispatch and useSelect hooks in the wp.data api found in the WordPress Gutenberg plugin. Note: the hooks will be available with the next release of the @wordpress/data package (which will happen after Gutenberg 5.9 is released)

So you’ve had a chance to finally figure out the wp.data api. You’ve written a few components using withSelect or withDispatch. You think you’ve got a handle on some of the finer points of higher order components in Gutenberg (and realize that’s essentially what withSelect or withDispatch are!). But now you start seeing things like useDispatch or useSelect pop up in use. What the heck are these? Where did they come from? Is everything you learned useless?

To answer the last question and appease your worries. No. Everything you’ve learned in using withSelect and withDispatch is still awesome. You can keep using them and your Gutenberg blocks and apps will still keep on rocking.

Read more “Fantastic hooks and where to use them.”

Testing Javascript for your Gutenberg Integrated Plugin

(Edit October 10, 2018) Note: This article is now out of date but is kept published for reference purposes. Nearly everything in Gutenberg is published as a package so for the purpose of testing you can include those packages as a devDependency in your package.json file and jest will know to reference those in tests. 

As a part of my work with Event Espresso I’ve been assisting them with moving over to a more modern Javascript build system.  This has been prompted by the upcoming new editor for WordPress codenamed Gutenberg.  I’m not going to spend a whole lot of time talking about Gutenberg since there’s already a ton of information on the internet.  What I want to do in this post is outline a way for plugin developers to test their custom components/blocks built for Gutenberg using the Jest framework.

Writing javascript tests using Jest is pretty straightforward and this isn’t a how-to-post since there’s a lot of that already available (including this readme the Gutenberg team prepared).  Instead I thought it’d be useful to write how I solved a problem with a particular set of tests I was trying to write for some code I had written (especially since I couldn’t find anything useful on the internet myself to help with it).

Read more “Testing Javascript for your Gutenberg Integrated Plugin”