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
- Example block: Major Link
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 (liketabindex
becomingtabIndex
) 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.