If you’ve been following my blog or WordPress development for some time now, you’d know by now that the Gutenberg project contains a number of hidden gems that you, as a JavaScript developer or a WordPress developer can benefit from in your own standalone applications or WordPress plugins.
One of these hidden gems is the keyboard shortcuts package, a utility package that allows you to do all sort of things related to keyboard shortcuts, between adding keyboard shortcuts, removing keyboard shortcuts, updating them and more.
As a standalone package.
Like any package in the gutenberg package, it’s distributed as a standalone npm package that you can consume and use in any React application. Here’s a basic example (Full example available on Stackblitz):
So to use the package, first, you need to wrap your React application in a ShortcutProvider. (The shortcuts will only work if the active element is inside the shortcut provider in the DOM tree)
The next step is to register your shortcuts using the registerShortcut action. This function call declares the existence of your shortcut in your shortcuts store, providing the keyboard combination used to trigger the shortcut behavior and some additional metadata, like a description and a category.
It’s a good practice to register all your shortcuts when initially rendering your application component.
That said, for the shortcuts to actually perform any action, we need to define their callbacks, and we do so using the useShortcut react hook, the first argument being the shortcut name and the second the function that is called when the key combination is pressed.
Note: The reason registering shortcuts and using shortcuts are separate is because some shortcuts are contextual to specific actions but the application always need to know about the existence of a shortcut during its lifecycle. For instance, all shortcuts can be rendered in a help panel but all the shortcuts might not be active. For example, a “copy” shortcut in an editor is only active if there’s a selection.
The keyboard shortcuts package allows using single character shortcuts or shortcuts with one or two modifiers. These are all examples of valid key combinations:
{ character: 'a' } is equivalent to pressing a.
{ character: 'del' } is equivalent to pressing the delete button.
{ character: 'a', modifier: 'primary' } is equivalent to pressing command + a on Mac.
{ character: 'a', modifier: 'primaryShift' } is equivalent to pressing command + shift + a on Mac.
{ character: 'a', modifier: 'alt' } is equivalent to pressing option + a on Mac.
As a WordPress API
In WordPress, the keyboard shortcuts package is used to register all the block editor shortcuts, but you can also use it to register your own custom shortcuts in your block or any WordPress plugin or page using the same API. It is available in the wp-keyboard-shorctuts wordpress script. If you plan on using it, in your plugin’s scripts, make sure to add the wp-keyboard-shorctuts as a dependency to your custom scripts:
The wp.keyboardShortcuts global variable will be made available for you with all the APIs exposed by the package: useShortcut, ShortcutsProvider…
Super Powers
Editing keyboard shortcuts
An important aspect of implementing keyboard shortcuts in any application is to define the right key combinations for the right shortcut. That said, it is surprisingly hard to come up with combinations that work for everyone, in all browsers and all operating systems. For that reason, the keyboard shortcuts package allows the possibility to update the registered shortcuts and change their keyboard combination.
import { useSelect, useDispatch } from '@wordpress/data';
import { store } from '@wordpress/keyboard-shortcuts';
function ToggleIncrementShortcut() {
const { getShortcutKeyCombination } = useSelect( store );
const { registerShortcut } = useDispatch( store );
const toggleShortcut = () => {
const currentCharacter = getShortcutKeyCombination( 'mycounter/increment' )?.character;
const nextCharacter = currentCharacter === 'a' ? 'i' : 'a';
registerShortcut( {
name: 'mycounter/increment',
description: 'Increment the counter',
keyCombination: {
character: nextCharacter
}
} );
}
return (
<button onClick={ toggleShortcut }>
Toggle between "i" and "a"
</button>
);
}
So as we can see in the example above, registering the shortcut again, overrides its current definition allowing us to update any of its properties including the key combination.
💡 In the future, the block editor might provide this automatically but until then, there’s an opportunity here for a WordPress plugin that provides a UI to edit the existing shortcuts.
This post presents different performance improvement and monitoring techniques that can be used in any React/Redux application.
Akin to the React Concurrent mode, it also introduces an async mode for Redux applications where the UI can’t be windowized.
WordPress 5.0 included a new block-based content editor. The editor is built as typical react/redux web application with a global store and a tree of UI components retrieving data using state selectors and performing mutations using actions.
Note To be more precise, The WordPress block Editor (called Gutenberg sometimes) uses multiple stores, but for the purpose of this post, we can simplify and assume it uses a single one.
Relying on the shoulders of giants: react-redux
The main performance bottleneck for most React/Redux applications is the fact that any change in the global state can potentially trigger updates in all the components subscribe to the store updates.
Fortunately, the simple fact of using react-redux is enough to solve most of these performance issues. The library is highly-optimized out of the box.
In the example above, each time the global state is changed, the mapStateToProps function is executed to compute the updated props passed to the underlying UI component.
By default if the computed props (block in our example) don’t change, the underlying component (Block in the example) is not re-rendered.
It’s important to note that react-redux‘s connect function performs a shallow comparison to check if the computed props changed or not. This means generating new object instances in mapStateToProps should be avoided and selectors (getBlock in our instance) should ensure that it returns the same block object instance on each call unless an actual change to the block object has been made.
// Bad: a new block object is generated on each render, causing rerenders even if the block name didn't change.
const mapStateToProps = state => ( {
block: { name: getBlockName( state ) }
} );
const MyBlockComponent = connect( mapStateToProps )( BlockComponent )
// Bad: Doing the same thing in a factorized selector is bad as well. It is strictly equivalent.
const getBlock = ( state ) => ( { name: getBlockName( state ) } );
Track component re-rendering
The first thing you should track when you notice performance degradations is whether you have components being re-rendered too often and without any meaningful prop change.
To do so, install the React Developer Tools browser extension, check the Highlight Updates option and notice the flashing borders around all the components being re-rendered. You can also inspect a given component and check which props are changing when it’s re-rendered.
Proxifying event handlers
Often, when react-redux‘s connect function, you end up providing event handlers that depend on props. For components optimized for purity (don’t render when props change), this can lead to unwanted rerenders because the event handler end-up being recreated on each render.
To address this issue @wordpress/data implemented its withDispatch higher-order component (equivalent to connect) with the idea that we only care about these event handlers when the event happens (click on a button…), so instead of recreating the event handler on each render, withDispatch provides proxies to the actual event handlers, these proxies instances don’t change per render and evaluate the actual event handlers when they get called. The assumption here is that the event handlers list won’t change depending on the component’s props.
Note that the data module offers now useSelect and useDispatch React hooks requiring a different technique to optimize event handlers that needs data dependencies.
Optimize the selectors
Now, that we ensured that our components re-render only if necessary (one of the props changed), we started monitoring our application to find the bottleneck.
When building an editor, one of the most important interactions you’d want to optimize for is “typing”. When quickly typing in the editor, the user shouldn’t notice slowness, the feedback (character being printed) should be immediate. Using the Chrome Performance Tools, we started monitoring the keypress event duration.
Keypress event monitoring
Quickly, we realized that the more content the editor is showing, the more rendered components we have, the worse the typing performance gets. And even if the components were memoized, their selectors were still being called on each change even if their result didn’t change. Selector calls quickly became the bottleneck of the editor’s performance. Our next step was to optimize the performance of our selectors.
The most important technique to be aware of here is what we call function memoization. Memoizing a function means that a function is not executed twice unless its inputs (arguments) change.
In the React/Redux world, there are a number of libraries allowing you to memoize selectors, some of the most used one being reselect and rememo.
Note Memoization is a good technique but it’s important to monitor and measure the performance improvements. Start by memoizing the less-performant selectors. Memoization is also a technique that can be used to avoid creating new objects/array instances if the inputs are the same (which then prevents components from re-rendering if not necessary).
Reshape the state tree to avoid high selector cache invalidation rates
In a typical Redux store, you’ll have some data that changes very often and other state values that don’t. It is important that these two things stay separate in the Redux state tree for better selector performance.
Let’s take the following blocks redux state as an example:
If we want to optimize the selector to avoid computing a new array if the state stays the same, we’d write something like:
const getBlockIds = createSelector(
state => state.blocks.map(block => block.id),
state => [ state.blocks ]
);
The second argument here tells the selector to avoid recomputing the array if the state.blocks value didn’t change.
That’s a good first step, the problem though is that we don’t reorder or add new blocks as often as we change the block attributes, the selector value won’t change, but the whole “blocks” state will causing the selector to recompute again.
This issue is solved by identifying what are the parts of the state that change often, and the ones that change less. Ideally, we should group all state values that change “together” under the same state key.
Here’s an example of a rewrite that can lead to better performance:
You’ll notice that now the array returned by getBlockIds won’t change unless the order or the list of blocks is actually changed. An update to the attributes of blocks won’t refresh the value returned by that selector.
Async mode
Memoizing slow selectors did have an impact on the performance but overall, the high-number of function calls (selector calls) was still an issue even if a single function call is very fast. It became apparent that instead of optimizing the selectors themselves, our best bet would be to avoid calling the selectors entirely.
This is a typical performance issue in React-Redux applications and the approach that most people take to solve is using windowing techniques. Windowing means that if a component is not currently visible on the screen, why do we need to render it to the DOM and keep it up to date. react-window is one of the most used libraries when it comes to implementing windowing in React applications.
Unfortunately, windowing is not an option we can consider for the block-editor for multiple reasons:
In general, windowing works by computing the height of the hidden elements and adapting the scrolling behavior to the computed height even if the elements are not rendered on the DOM. In the case of the block editor, it’s actually impossible to know or compute the height of the blocks and their position without really rendering them to the DOM.
Another downside is the A11y support, screen readers tend to scan the whole DOM to provide alternative ways to navigate the page without relying on a notion of “visible elements” or not. Something that is not rendered on the DOM, is something you can’t navigate to.
For these reasons, we had to be a bit more innovative here. While the initial rendering of the components had a cost, the most important thing for us is to keep the UI responsive as we type, and the bottleneck at this point was the number of selectors being called.
That said, in a typical block editor, when you’re editing a given block, it is very rare that an update to that block affects other parts of the content. Starting from this hypothesis, we implemented the Async Mode.
What is the Data Module’s async mode?
The Async mode is the idea that you can decide whether to refresh/rerender a part of the React component tree synchronously or asynchronously.
Rendering asynchronously in this context means that if a change is triggered in the global state (Redux store), the subscribers (selectors) are not called synchronously, instead, we wait for the browser to be idle and perform the updates to React Tree.
It is very similar to the Concurrent mode proposed by the React Team in the last React versions. The difference is that React’s concurrent mode use setState calls to defer the rendering but in our case, we want to defer the selector calls which in the call chain happen before the React setState calls.
How did we apply the async mode to the editor?
Our approach was to consider the currently selected block as a synchronous React component tree, while considering all the remaining blocks as asynchronous.
It is possible to opt-out of Async mode for a given block. This can be useful for blocks that rely on other blocks to render properly. (E.g. Table of content block)
At this point, our biggest performance issues were solved, but still, we wanted to continue improving the editor’s performance as much as we can.
What’s next
Building a performant editor is a challenge, an on-going one, and unlike regular features, performance is not something you can implement and forget about, it’ts a continuous workflow. If you have to take something out of my lenghty blog post, I hope it’s this:
Identify the flows you want to optimize,
Identify the bottlenecks of your application,
Measure constantly, ideally in an automatic way on each PR,
Don’t learn and apply optimization techniques blindly, instead, read about them, know their existence and try to adopt the best techniques based on your particular use-cases.
The WordPress block editor is based around the idea that you can combine independent blocks together to write your post or build your page. Blocks can also use and interact with each other. This makes it very modular and flexible.
But the Block Editor does not embrace modularity for its behavior and output only, it is also built from the ground up as several reusable and independent modules or packages, that, combined together lead to the application and interface we all now. These modules are known as WordPress packages and are published and updated regularly on the npm package repository.
Right now these packages are built in the Block Editor Repository and used to power the block editor. Ultimately, these packages will be used to power any page in the WordPress Admin.
Modular architecture
Using a modular architecture has several benefits for all the actors involved:
Each package is an independent unit and has a well defined public API that is used to interact with other packages and third-party code. This makes it easier for Core Contributors to reason about the codebase. They can focus on a single package at a time, understand it and make updates while knowing exactly how these changes could impact all the other parts relying on the given package.
A module approach is also beneficial to the end-user. It allows to selectively load scripts on different WordPress Admin pages while keeping the bundle size contained. For instance, if we use the components package to power our plugin’s settings page, there’s no need to load the block-editor package on that page.
This architecture also allows third-party developers to reuse these packages inside and outside the WordPress context by using these packages as npm or WordPress script dependencies.
Types of packages
Almost everything in the Gutenberg repository is built into a package. We can split the packages into two different types:
Production packages
These are the packages that ship in WordPress itself as JavaScript scripts. These constitute the actual production code that runs on your browsers. As an example, there’s a components package serving as a reusable set of React components used to prototype and build interfaces quickly. There’s also an api-fetch package that can be used to call WordPress Rest APIs.
Third-party developers can use these production packages in two different ways:
If you’re building a JavaScript application, website, page that runs outside of the context of WordPress, you can consume these packages like any other JavaScript package in the npm registry.
npm install @wordpress/components
import { Button } from '@wordpress/components';
function MyApp() {
return (
<Button>Nice looking button</Button>
);
}
If you’re building a plugin that runs on WordPress, you’d probably prefer consuming the package that ships with WordPress itself. This allows multiple plugins to reuse the same packages and avoid code duplication. In WordPress, these packages are available as WordPress scripts with a handle following this format wp-package-name (e.g. wp-components). Once you add the script to your own WordPress plugin scripts dependencies, the package will be available on the wp global variable.
// myplugin.php
// Exemple of script registration dependending on the "components" and "element packages.
wp_register_script( 'myscript', 'pathtomyscript.js', array ('wp-components', "wp-element" ) );
// Using the package in your scripts
const { Button } = wp.components;
function MyApp() {
return (
<Button>Nice looking button</Button>
);
}
Some production packages provide stylesheets to function properly.
If you’re using the package as an npm dependency, the stylesheets will be available on the build-style folder of the package. Make sure to load this style file on your application.
If you’re working in the context of WordPress, you’ll have to enqueue these stylesheets or add them to your stylesheets dependencies. The stylesheet handles are the same as the script handles.
In the context of existing WordPress pages, if you omit to define the scripts or styles dependencies properly, your plugin might still work properly if these scripts and styles are already loaded there by WordPress or by other plugins, but it’s highly recommended to define all your dependencies exhaustively if you want to avoid potential breakage in future versions.
Packages with data stores
Some WordPress production packages define data stores to handle their state. These stores can also be used by third-party plugins and themes to retrieve data and to manipulate it (Refer to my previous post on the subject for more details here). The name of these data stores is also normalized following this format core/package-name (E.g. the @wordpress/block-editor package defines and uses the core/block-editor package).
If you’re using one of these stores to access and manipulate WordPress data in your plugins, don’t forget to add the corresponding WordPress script to your own script dependencies for your plugin to work properly. (For instance, if you’re retrieving data from the core/block-editor store, you should add the wp-block-editor package to your script dependencies like shown above).
Development packages
These are packages used in development mode to help developers with daily tasks to develop, build and ship JavaScript applications, WordPress plugins and themes. They include tools for linting your codebase, building it, testing it…
Going further
The WordPress packages are a gold mine and a huge time saver when it comes to building JavaScript application whether as a WordPress plugin or an independent application.
In the next weeks, I’ll try to write a series of posts to explain some of these packages in detail, how to reuse them in your own code. In the meantime, I encourage you to explore the documentation of the different packages on the block editor handbook.
With Gutenberg, we made the choice to use JavaScript heavily in order build the UI of the editor, not because we’re nerdy hipsters but essentially because it is the perfect fit to address the UI and UX challenges of a heavily interactive interface in the browser.
As a consequence, we’ll start to see a shift in the WordPress community. Plugin developers are required to use JavaScript more in order to extend the editor. Most blocks need to be developed using this technology. The modules Gutenberg provides (Components, data module, i18n, apiFetch…) will also encourage developers to extend other parts of WP-Admin in JavaScript. Instead of writing HTML/CSS screens from scratch and rendering them from the server, developers are able to bootstrap and prototype fully accessible new screens in WP-Admin by composing these components in a small number lines of code.
Learning process
But when we talk about JavaScript in general, we can think of two different approaches:
Using untranspiled ES5 code.
Leveraging build tools like babel, webpack… and write ESNext JavaScript code (ES2015 and more).
Most plugin authors are already writing ES5 code in their PHP rendered UIs or in their themes and the Gutenberg APIs can continue be used this way. But our role as Core Contributors should also be to educate people to get on the ESNext train as it can be a huge improvement in terms of productivity and development experience.
That said, learning ESNext and all the tools involved in the process can be a bit overwhelming if you’re coming from a PHP background without any prior heavy JavaScript experience. To help with the transition, the WordPress community started working and providing tools (Like Create Guten Block).
Using these tools can feel like “magic” though. It works but as a developer, you don’t really know what’s happening behind the scenes. Debugging code can be a challenge if you don’t understand how everything fits together.
For this particular reason, I created the WordPress JavaScript Plugin Starter. Unlike other starters thought, it’s written as a tutorial. Each commit of the repository is a step further in the setup and the README goes through each one of these steps and explains it.
Hopefully, At the end of the day, you’d be able to use the starter as a way to start a WordPress plugin but also master how this plugin works and how all the tools fit together to ship a production ready JavaScript plugins.
Manipulating Client Data in highly interactive screens in WordPress (essentially the editor page in WordPress pre 5.0.0) is not the easiest task to do for plugin authors. As much as WordPress provides a large number of functions to access and manipulate data server side, it fails at providing a consistent way to access and manipulate data on the client.
And by client side data, I refer to things like:
What’s the current post content in the editor? How can I update it programmatically?
What’s the currently selected tags/categories?
Is a given metabox visible or not?
How can I be notified if an image block is inserted into the editor of if the user switches the post status?
Client-data is also about accessing the WordPress REST API Data client-side:
How do I retrieve the latest posts?
How do I retrieve the current user’s object?
How can I create a new Category?
And it can also encompass plugins data. For example:
How do I store/update and access my own plugins client-side data?
How do I access and update the content of the Yoast metabox?
How do I retrieve the content of ACF metaboxes in a custom ACF plugin?
Often, to address these use-cases, we had to manipulate the DOM directly: Retrieve input’s values directly from the DOM or subscribe to DOM events to ensure we’re notified properly. This often leads to hacky code and code that breaks on WordPress/plugin updates because DOM access is not an official extensibility API.
Gutenberg JavaScript-heavy World
With Gutenberg’s release coming and as we add more and more JavaScript-powered UI to WordPress pages, the need for a consistent solution to manage client-side data is urgent, we can’t rely on DOM access anymore. To address this, Gutenberg introduces the Data Module.
Retrieving Data
One of the first use-cases of the Data module is to retrieve data defined by WordPress. To do so, you need to specify the namespace of the data to call a selector on this namespace.
Here’s how we retrieve the content of the post being edited in a Gutenberg Page.
var content = wp.data.select( 'core/editor' ).getEditedPostAttribute( 'content' );
Notice that the data module API is available in the wp.data global variable. The namespace to access the editor’s data is core/editor. And in each namespace, you can use a list of selectors.
A selector is a simple JavaScript function used to retrieve client-side data. In the example above, the selector being called is getEditedPostAttribute. This selector accepts an argument corresponding to the post attribute to retrieve. If we need to retrieve the title of the post instead of its content, we can do:
var title = wp.data.select( 'core/editor' ).getEditedPostAttribute( 'title' );
Protip: The list of the available selectors/namespaces is not documented properly on WordPress/Gutenberg yet. To see the full list of the core/editor‘s selectors, you can check the selectors file here.
You can also type wp.data.select( 'core/editor' ) in your browser’s console in any Gutenberg page to inspect the full list of the selectors available in this namespace.
Updating Data
So, selectors allow us to retrieve data and similarly, each namespace can defined actions to manipulate data (create/update/remove). For example, to update the title of the post being edited in Gutenberg, you can do:
wp.data.dispatch( 'core/editor' ).editPost( { title: 'My New Title' } );
An action is a function called to update the client-data defined in a given namespace.
Protip: To see the full list of the actions defined by the core/editor namespace, you can check the actions file here. You can also type wp.data.dispatch( 'core/editor' ) in your browser’s console in any Gutenberg page to inspect the full list of the actions available in this namespace.
Register a custom “namespace”
Plugins can also manage their client state using the data module. To achieve this, they need to register their selectors/actions in addition to a reducer to hold and update the state.
A reducer is a function describing the shape of the initial state and how the state value evolves in response to dispatched actions.
Protip: The Data module is built on-top of the redux library. Learning redux is not required to use it but taking a look at the Redux Docs and its glossary should help you master the data module.
As an example, Let’s register a custom store to keep track of a list of todo items:
// This is the reducer
function reducer( state = [], action ) {
if ( action.type === 'ADD_TODO' ) {
return state.concat( [ action.todo ] );
}
return state;
}
// These are some selectors
function getTodos( state ) {
return state;
}
function countTodos( state ) {
return state.length;
}
// These are the actions
function addTodo( text, done = false ) {
return {
type: 'ADD_TODO',
todo: { text: text, done: done };
};
}
// Now let's register our custom namespace
var myNamespace = 'my-todos-plugin';
wp.data.registerStore( myNamespace, {
reducer: reducer,
selectors: { getTodos: getTodos, countTodos: countTodos },
actions: { addTodo: addTodo }
} );
Now that the custom namespace is registered, we can consume this in our code, the same way we did for the core/editor’s store.
// Add a new todo item
wp.data.dispatch( 'my-todos-plugin' ).addTodo( 'Finish writing a blog post about the data module', false );
// Retrieve the list of todos
var countTodos = wp.data.select( 'my-todos-plugin' ).countTodos();
React to changes in the state
Another important use-case for WordPress Plugins often is to react to changes happening in Core Data or other plugins. To address this, the Data Module provides a subscribe function. This function allows registering listeners that get called each time the state is changed.
In the following example, we trigger some random behavior each time a new block is added to the editor:
var currentCount = wp.data.select( 'core/editor' ).getBlockCount();
wp.data.subscribe( function() {
var newCount = wp.data.select( 'core/editor' ).getBlockCount();
var hasNewBlocks = newCount > currentCount;
currentCount = newCount;
if ( hasNewBlocks ) {
// A new block has been added, do something
console.log( 'The new block count is :' + newCount );
}
} );
Declarative data needs
In addition to a new way to handle data client-side, as WordPress and plugins move towards more JavaScript UIs, the use of React and its wordpress abstraction wp.element is growing.
The WordPress element module allow you to describe UI using functions (or components) taking props and returning an HTML representation of the component.
A simple component displaying an h1 can be written like so:
// You can use JSX instead of wp.element.createElement
var el = wp.element.createElement;
function Title( props ) {
return el( 'h1', {}, props.title );
}
Very often, these UI components need data to work properly. In the example above, the Title component expects a title prop to display its content in an h1.
Let’s say we’d like to display title component using the title of the post being edited in Gutenberg, we can use the select function explained previously and do something like that:
But this approach has some downsides. The value of the title prop can change over time and we’d like to refresh our component once that happens. This means we need to use wp.data.subscribe and rerender each time the title changes.
Fortunately, to avoid having to write this logic for ourselves, The data module provides what in the React community is referred to as a Higher-order component. A Higher-order component is a function that wraps another component and feeds it with props.
Here’s how you provide the title as a prop using the data module:
Now when we render the EditorPostTitle component, it will be automatically refreshed each time the title value changes.
el( EditorPostTitle );
Similarly to how the withSelect Higher-order component provides props to components using selectors, the data module also provides a withDispatch Higher-order component to feed components with actions.
Let’s write an input that can be used to change the value of the Gutenberg’s post title.
Notice in this example how we’re composing both withSelect to retrieve the current title and withDispatch to provide a onChangeTitle callback the input Component can call to perform the updates.
Protip: Notice the compose function being used in the example, it’s an utility function that allow combining several Higher-order components together.
Until now, we were mostly dealing with synchronous selectors and actions but WordPress Data offers a way to handle asynchronous data as well.
To do so, we can attach a side-effect to each selector: A function that gets executed the first time a selector is called with a given set of arguments. This function can be responsible of performing an async API request and updating the state once the request succeeds. These side-effect functions are called resolvers.
For instance, we might be interested to fetch posts list to display them in a PostList component.
var el = wp.element.createElement;
// This a UI component showing a list of post titles given a posts prop.
function PostList( props ) {
return props.posts.map( function( post ) {
return el( 'div', { key: post.id }, post.title.rendered );
} );
}
var RecentPostList = wp.data.withSelect( function( select ) {
posts: select( 'core' ).getEntityRecords( 'postType', 'post' )
} );
Notice that in this example, the APIs being used are the same we were using before, but behind the scenes, a REST API is being executed the first time the getEntityRecords selector is called, to fetch the post list.
Here’s the exact flow:
The first time the getEntityRecords selector is called, the post list is empty. So the PostList component is rendered with an empty list of posts.
But behind the scenes the core data module also calls the resolver called getEntityRecords to perform the API Request for you.
When the API Request resolves, the state is updated with the received posts. This will automatically retrigger a rerender, thanks to the way withSelect works.
The PostList gets rerendered with the update list of posts.
Protip: If you’re interested in implementing this kind of side effects in your own plugins, make sure to take a look at the resolvers in the Data module docs.
WordPress Headless / Agnostic?
The Data Module is a generic JavaScript package to handle data, if you want to use in a WordPress client, or if you want to use any applications not related with WordPress, that’s also possible. Instead of using the wp.data global, you can just fetch the package from npm:
npm install @wordpress/data --save
Going further
The Data Module is still being enhanced, if you’re Interested in learning more about the Data Module or any other modules, make sure to join the #core-js channel of the WordPress Core slack and the weekly meetings happening each Tuesday at 13:00 UTC.
Do you know WordPress, this tool that powers 27% of the web? This big old CMS everyone loves to hate because It’s oldish, it’s PHP and it’s not an SPA? but in the same time, everyone uses because it’s so great at achieving the goal it’s designed for: creating content? Well! It’s time to stop criticizing and take a look at what’s happening in the WordPress community and what we’ll get for the next iteration of our beloved CMS? (more…)
When we hear about GraphQL, it’s often mentioned as the new way to retrieve data from the server. The silver bullet that will replace REST APIs. This is true, GraphQL can do an amazing job to run the new generation of server APIs but this is not the whole picture.
From the homepage of the official website, GraphQL is described as “A query language for your API” where you:
First, describe your data
Then, ask for what you want
Finally, obtain predictable results
We quickly make the assumption that it allows us to query server APIs using HTTP requests but if we take a deeper look at the official JavaScript implementation, we understand that this is not totally true, GraphQL is a query language for any Data Provider whether it’s local or remote.
Many Tools have been developed to ease the use of GraphQL server-side: From Relay, Apollo Data Tools, express-graphql etc… but few people focused on using it on the client. While you’ll probably get the most of it, if it’s used server-side, using GraphQL on the client can be valuable as well and often, using GraphQL on the server requires a big investment where you probably have to rewrite your entire application to make the transition.
A typical React/Redux application
In the React Ecosystem, a large number of applications are using Redux to store their data in a global state tree. How can we use GraphQL to improve the architecture of such applications without rewriting our application from scratch?
So first, let’s try to take a look at a typical React/Redux Application (A Todo Application of course). We’ll probably have:
A reducer that “stores” the data in the global state: todos reducer,
An action creator used to retrieve todos from the server: fetchTodos
In most cases, This action creator will rely on redux-thunk to trigger a network request and dispatch the action once the results retrieved.
A selector getTodos responsible of retrieving the todos from the global state
And to link all of these items together, we would use react-redux to bring our data and action creators to our component. A complete TodoList React Component could look like that:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Let’s take a deeper look at this component. It has three responsibilities:
It triggers an action creator to fetch Data
It uses a selector to retrieve Data from the redux tree
And it renders the Data
React’s main purpose is providing a declarative API, to express how your data get transformed into DOM elements, but in our example above, the fetching and data retrieval is imperative. This means it’s the responsibility of the persons who write the component to trigger the data fetching requests and eventually handles data refreshing. And in this area, Relay has been doing a great job to transform these imperative calls into a declarative API. What if we could provide a declarative API (similar to Relay) without the need of rewriting our APIs to use GraphQL? and without even using Relay?
We want our component to be written like this:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
If we need more data such as the authenticated user, our query could be:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Basically, we use a Higher Order Component called query to declare that our component needs a list of todos, and for each todo, we want its id, text, and done attributes. We don’t mind how this data is fetched from the server or retrieved from the redux store, we just declare what data the component needs and it will be made available as a prop.
How is this possible?
Ok! this sounds awesome right! but isn’t this too difficult to achieve, how do we match each part of this query to its corresponding actions / selectors?
We need a tree resolution algorithm where we match each node of the tree to a function that fetches and retrieves this data. And you know!! this is exactly the purpose of GraphQL. A way to match a query to resolvers.
Ok! Let’s setup GraphQL to resolve the query above:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
The idea here is for every node of our query, we write:
1- A schema: A good side effect of using GraphQL is the schema which will be used to validate our data. This ensures a valid data is provided to all your React Components.
2- A resolver: A function with the following shape:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Make our GraphQL resolvers available for the query HoC
Now that our GraphQL setup is ready, we can make it available on the React context, that way the query HoC can use it to provide data to the wrapped components. This is the exact same technique used by react-redux to make the store available for connected components.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Now, you are ready to go! wrap your components with query HoC.
Is this worth it?
If you’re working on a small application with dozen of actions and selectors, probably not. Just stick with the imperative fetching, but If your application is big enough, I would say, this is certainly worth a try.
Good benefits
I already mentioned the fact that using GraphQL allows you to validate your data, you are certain that the data provided to your components would always be valid against the defined schema.
Another good side effect is the possibility to use GraphiQL. If you’re not familiar with it yet, it’s a web interface which allows you to test your GraphQL queries before using them in your components. Also, it allows you to navigate through your data which increases data discoverability a lot. You won’t lose your time looking or rewriting existing redux selectors, if the data is already available, you’ll just find it in GraphiQL.
Library
You can find the query HoC and the GraphProvider in this library, but it’s easy enough to write on your own if you prefer to.
Who is using this approach already?
Me:). I don’t know if anyone else is but we’re considering using it for Calypso, the new WordPress.com front-end. Here is the PR
Time to get your hands dirty! and let me know if you have any thoughts or concerns on this 🙂
I have to admit, It took me some time to figure out in which use cases ES6 generators could be really useful (I’m not the only one I think, am I ?). When we talk about ES6 (or ES2015 as you like), generators are not the first feature we think about, we often see them as an easy way to create custom iterators, but in reality they are much more than that, they are maybe one of the most interesting features added in ES6. (more…)
There’s this expression I say each time I stumble on something (some technology) that’s going to change my habits in development …. Oh, ça déchire sa mère 😛 a not so conventional french alternative to wow that’s great !!!.
And you know what, It just happened again. I discovered redux-saga, And I’m like: “Wow this is great, that’s exactly what I was looking for”
Unidirectional data flow (or sometimes referred to as reactive programming or functional programming) is often seen as this new trend in frontend applications development brought by React and Flux (or by ReactiveX from Netflix). So many developers think using one of these libraries or frameworks is necessary to start with this pattern. This, of course, is not true. I can use React and don’t have an unidirectional data flow at all, and the opposite, I can use stacks not designed with functional reactive programming in mind and still have an unidirectional data flow.