A Crash Course in React for Gutenberg

About this document

Note: This was prepared for a developer retreat in March of 2018, as such it doesn’t necessarily reflect the latest in React or Gutenberg, but most of the information remains true.

Mostly the goal here is just to give an outline of some things to know and some information about them I’m not going in too deep to anything, so check out the official react docs if you want more information.

Some Resources:

https://reactjs.org/docs/hello-world.html – Official React Docs

https://github.com/WordPress/gutenberg – Gutenberg Git Repo with some good info

https://wordpress.org/gutenberg/handbook/ – Gutenberg Handbook, just general info

https://riad.blog/2017/10/16/one-thousand-and-one-way-to-extend-gutenberg-today/ – Some specific code samples of how to use Gutenberg

https://github.ncsu.edu/ncstate-wordpress/ncsu-blocks/ – Our homegrown NC State Content Blocks plugin

What is React

Boiled down, React is basically just a way of generating a bunch of HTML to output to the browser based on data and the output of javascript functions, rather than writing a bunch of HTML and sort of grafting javascript on to it to change what is displayed. You don’t have to worry about what content is in the HTML because it all derives from the javascript as the source of truth.

React Components

React Components are basically just javascript Objects. They can have Props and State

Props are passed to a component when it is rendered, similar to attributes of an HTML tag or shortcode, if you had a component that was a toggle switch, the label would probably be passed in as Props

State is created when the component is rendered, and can be changed from within the component itself. For a toggle switch component, whether it is toggled on or off would be part of the State

The distinction is a little bit arbitrary because you might set the state to a value based equal to the props, but generally you want to keep as much of the data as Props as possible because it is easier to work with and has some performance benefits.

Types of Components

There are two types of components Class based and Functional (aka Stateless)

Class Based

Class based components are more verbose to write, but they can have State, and Utilize Lifecycle methods. Lifecycle methods are functions that will run at different points in the rendering process, if you want to do something before the component renders, after it has rendered, when it is unmounted etc. you need lifecycle methods

Here is an example of a Class based component (Taken from the React Docs)

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }

  componentDidMount() {
    this.timerID = setInterval(
      () => this.tick(),
      1000
    );
  }

  componentWillUnmount() {
    clearInterval(this.timerID);
  }

  tick() {
    this.setState({
      date: new Date()
    });
  }

  render() {
    return ( Hello, world! It is {this.state.date.toLocaleTimeString()}. );
  }
}

This component is using 3 lifecycle methods, componentDidMount, componentWillUnmount, and render. The tick method is called by the componentDidMount and the constructor method is called when the component initializes and sets the initial state. More info on lifecycle here: https://engineering.musefind.com/react-lifecycle-methods-how-and-when-to-use-them-2111a1b692b1

Functional

Functional Components are much more simple to write, but they don’t get state or lifecycle components.

Here is an example of the real live functional component for the MajorLink

var MajorLink = function (props) {
        return (
             a className='...' href={props.href} onClick={props.onClick || null} 
                {props.children}
                 span className='right-arrow' aria-hidden='true' 
                     svg version='1.1' width="32" height="32" viewBox="0 0 32 32" 
                         path d='...' / 
                     /svg 
                 /span 
             /a 
        );
    }

Notice that there is no class extends code, it is just a function assigned to a variable (important note: Components must always be given uppercase names, this is how they are distinguished from regular HTML tags). There are no methods, though you could have another function inside this function. Basically this whole component is the same as the render method from a class based component. Also note that the class based component must use this.state or this.props to refer to its props, whereas the functional component can just call props (as it should always be set as a parameter of the function).

JSX

You’ll notice that the examples the previous section use what looks like HTML inside the JavaScript, this is JSX.

Under the hood to create elements you need to use the React.createElement() function (WordPress aliases this to wp.createElement() for various reasons). This function takes three parameters, the tag (or component), the props, and the children. So to create a link to google you would do something like 

React.createElement(‘a’, {href:’http://google.com’, target:’_blank’}, ‘Link to Google.com’)

That’s not too bad for that element but it gets harder when you start nesting a bunch of elements together and is much harder to read. JSX just lets you write this same information in a way that is closer to HTML but can be converted to the correct function at build time, that same code again converted to JSX looks like

 a href="http://google.com" target="”_blank”" rel="noopener noreferrer" Link to Google.com /a 

Much more familiar and easy to anyone who knows HTML, but there are a few key differences (And I’m sure I’m missing some) :

  • You have to use className instead of class for the class attribute, this is to differ it from the technical javascript class, there are a few other changes like this  (like tabindex becoming tabIndex) but this is the biggest one.
  • All JSX tags must have a closing slash
  • Anything that’s not a standard html tag must start with a capital letter

Any javascript expression can be passed as props or used within JSX, just make sure to surround it with curly brackets, props that are just strings can use quotes around them, for example:

 a href={props.linkURL} className=”my-string-class” target=”_blank” rel="noopener noreferrer" Link to {props.linkName} /a 

 An important thing to remember is that JSX expressions are just functions, and functions can be passed around as values in javascript, so you could pass a JSX expression as props, conditionally render jsx, or loop over data and run jsx for each iteration. 

You don’t have to use JSX, and if you are using JSX you will need to use some build step, like transpiling with Babel, to convert your code into something that will run in the browser, but it makes working with the code a lot easier than nesting createElement functions.

More info here: https://reactjs.org/docs/introducing-jsx.html and here: https://reactjs.org/docs/jsx-in-depth.html

Gutenberg

Gutenberg is based around blocks and lets you create React components that will render the HTML that will be on the front end of the site as well as what will show when a user is editing the post. 

Creating a Gutenblock

Blocks are registered with the javascript function registerBlockType(), this function takes two parameters, the block name (in the format of ‘namespace/name’ like 'ncsu-blocks/major-link') and the block configuration object, which is where all the real fun happens.

The Block Configuration Object

The main properties for the block object are title, icon, category, attributes edit, and save. 

Basic Properties

Title is the human readable title. Icon is the icon name, the WordPress dashicons are included by default. Category will determine which section that the block will show up in when users go to add a block, the default is ‘common’.

Attributes

Attributes are used to map the information saved in the HTML in the database to the JavaScript representation in Gutenberg. Essentially these will be the Props provided to the React Components in your Gutenblock that users will be able to change.

For instance, take the Major link, the important parts that the user needs to be able to change is the URL and the Link text. The class and other attributes will always be the same so they can just be hard coded in.

attributes: {
            content: {
                source: 'text',
                selector: 'a'
            },
            href: {
                source: 'attribute',
                selector: 'a',
                attribute: 'href'
            }
        },

You can see that each attribute is given a name (content, and href in this case, they can be whatever you want to define them as in your code), a source (the content comes from the text of the element, the href comes from an attribute of the element), and in the case of the href, because if is coming from an attribute you have to say which attribute it is coming from. 

There is a lot more you can do with attributes, see more info here: https://wordpress.org/gutenberg/handbook/block-api/attributes/

Edit

The edit property is essentially a functional component that takes a single parameter, props. The return of this function is what will be displayed on screen while the post is being edited. 

Props is an object with a number of properties, but I am going to focus on the two important ones here

attributes

An object containing the attributes as defined in the main attributes property of the configuration object.

setAttributes()

To change the Attributes of the block, the properties should not be set directly, but you should use the setAttributes method to do this.

Save

Similar to the edit method, this is a functional component that takes a single props parameter. The output of this function is what will be saved to the database as the content to eventually be rendered on screen. In the case of Dynamic Blocks, the save method should return null.

The props parameter passed to the save method has a single property, attributes, which is the same as the attributes property on the edit method.

Dynamic Blocks

Most blocks are static blocks, in that every time you reload the page, the same data will be delivered to the browser. You can however create Dynamic blocks, for which the data is determined when the request for the page is made. Dynamic blocks have the save method in javascript return null, and a render callback is provided in a PHP file.

The register_block_type() function in PHP is similar to the javascript one, it takes a name and a configuration array. The configuration array should have an attributes array and a render callback. The render callback is passed the attributes array and should return the HTML to display.