Although Gutenberg is put together with React, the code we’re writing to make custom blocks isn’t. It certainly resembles a React component though, so I think it’s useful to have a little play to get familiar with this sort of approach. There’s been a lot of reading in this series so far, so let’s roll-up our sleeves and make something cool.
Article Series:
Series Introduction
What is Gutenberg, Anyway?
A Primer with create-guten-block
Modern JavaScript Syntax
React 101 (This Post)
Setting up a Custom webpack
A Custom “Card” Block
Let’s make an “About Me” component
We’re going to make a single React component that updates the background color of a page and the intro text based on data you input into a couple of fields. “I thought this was supposed to be cool,” I hear you all mutter. I’ll admit, I may have oversold it, but we’re going to learn some core concepts of state-driven JavaScript which will come in handy when we dig into our Gutenberg block.
For reference, this is what we’re going to end up with:
Getting started
The first thing we’re going to do is fire up CodePen. CodePen can be used for free, so go head over there and create a new Pen.
Next, we’re going to pull in some JavaScript dependencies. There are three editor screens—find the JS screen and click the settings cog. This will open up a Pen Settings modal where you’ll find the section titled Add External Scripts/Pens. Right at the bottom, theres a Quick-add select menu. Go ahead and open that up.
From the menu, select React. Once that’s selected, open the menu and select ReactDOM. You’ll see that this has pre-filled some text boxes.
Lastly, we need to enable our ES6 code, so at the menu titled JavaScript Preprocessor, select Babel.
Now, go ahead and click the big Save & Close button.
What we’ve done there is pull the main React JS library and ReactDOM library. These will enable us to dive in and write our code, which is our next step.
Setup our CSS
Let’s make it look cool. First up though, let’s setup our CSS editor. The first thing we’re going to do is set it up to compile Sass for us. Just like we did with the JS editor, click on the settings cog which will bring up the Pen Settings modal again—this time with the CSS settings.
At the top, there’s a CSS Preprocessor menu. Go ahead and select SCSS from there.
When that’s done, go down to the Add External Stylesheets/Pens and paste the following three links into separate text-boxes:
https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.0/normalize.css
https://fonts.googleapis.com/css?family=Work+Sans:300
https://rawgit.com/hankchizljaw/boilerform/master/dist/css/boilerform.min.css
Those three in order give us a reset, a fancy font and some helpful form styles.
Now that they’re all set, go ahead and click the “Save & Close” button again.
Adding a bit of style
We’re all setup so this step should be easy. Paste the following Sass into the CSS editor:
:root {
–text-color: #f3f3f3;
}
* {
box-sizing: border-box;
}
html {
height: 100%;
font-size: 16px;
}
body {
height: 100%;
position: relative;
font-size: 1rem;
line-height: 1.4;
font-family: Work Sans, sans-serif;
font-weight: 300;
background: #f3f3f3;
color: #232323;
}
.about {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
color: var(–text-color);
transition: all 2000ms ease-in-out;
&__inner {
display: flex;
flex-direction: column;
height: 100%;
margin: 0 auto;
padding: 1.2rem;
}
&__content {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
flex: 1 1 auto;
font-size: 3rem;
line-height: 1.2;
> * {
max-width: 30ch;
}
}
&__form {
display: flex;
flex-direction: column;
align-items: center;
padding: 2rem 0;
width: 100%;
max-width: 60rem;
margin: 0 auto;
@media(min-width: 32rem) {
flex-direction: row;
justify-content: space-between;
padding: 2rem;
}
> * {
width: 15rem;
}
> * + * {
margin: 1rem 0 0 0;
@media(min-width: 32rem) {
margin: 0;
}
}
label {
display: block;
}
}
}
// Boilerform overrides
.c-select-field {
&,
&__menu {
width: 100%;
}
}
.c-input-field {
width: 100%;
}
.c-label {
color: var(–text-color);
}
That’s a big ol’ chunk of CSS, and it’ll look like nothing has really happened, but it’s all good—we’re not going to have to worry about CSS for the rest of this section.
Digging into React
The first thing we’re going to do is give React something to latch on to. Paste this into the HTML editor of your Pen:
That’s it for HTML—you can go ahead and maximize your JS editor so we’ve got complete focus.
Let’s start our component code, by creating a new instance of a React component by writing the following JavaScript:
class AboutMe extends React.Component {
}
What that code is doing is creating a new AboutMe component and extending React’s Component class, which gives us a load of code and tooling for free.
Right, so we’ve got a class, and now we need to construct it! Add the following code, inside the brackets:
constructor(props) {
super(props);
let self = this;
};
We’ve got a few things going on here, so I’ll explain each:
constructor is the method that’s called when you write new AboutMe(), or if you write
super is how we tell the class that we’ve extended to construct with its own constructor. You’ll see we’re also passing the props up to it in case any parent components need to access them.
Finally let self = this is a way of controlling the scope of this. Remember, because we’re using let, self will only be available in the constructor function.
Quick note for those readers not-so-confident in JavaScript: I found a deeper look at scope in JavaScript to result in a lot of “aha” moments in my learning. I highly recommend Kyle Simpson’s You Don’t Know JS book series (available for free on GitHub!). Volumes of note: this and Object Prototypes and Scope & Closures. Good stuff, I promise.
Now we’ve covered the constructor, let’s add some more code to it. After the let self = this; line, paste the following code:
self.availableColors = [
{
name: Red,
value: #ca3814
},
{
name: Blue,
value: #0086cc
},
{
name: Green,
value: #3aa22b
}
];
What we’ve got there is an array of objects that define our options for picking your favorite color. Go ahead and add your own if it’s not already there!
Your class definition and constructor should now look like this:
class AboutMe extends React.Component {
constructor(props) {
super(props);
let self = this;
// Set a list of available colors that render in the select menu
self.availableColors = [
{
name: Red,
value: #ca3814
},
{
name: Blue,
value: #0086cc
},
{
name: Green,
value: #3aa22b
}
];
};
}
Pretty straightforward so far, right? Let’s move on and set some initial values to our reactive state. Add the following after the closing of self.availableColors:
// Set our initial reactive state values
self.state = {
name: Foo,
color: self.availableColors[0].value
};
This initial setting of state enables our component to render both a name and a color on load, which prevents it from looking broken.
Next, we’ll add our render function. This is a pure function, which does nothing but render the component based on the initial state or any state changes during the component’s lifecycle. You may have guessed already, but this is where the main body of our JSX lives.
Wait up! What’s a pure function? Welcome to functional programming, a hot topic in the React world. Pure functions are functions where, for input X, the output will always be Y. In an “impure” function, input X might result in different outputs, depending other parts of the program. Here’s a CodePen comparing pure and impure functions. Check out this article out, too, for more details.
Now, because there’s quite a lot of markup in this single component, we’re going to copy the whole lot into our function. Add the following under your constructor:
render() {
let self = this;
return (
Hello there. My name is { self.state.name }, and my favourite color is { self.getActiveColorName() }
: null }
);
};
You may be thinking something like: “Holy cow, there’s a lot going on here.” Let’s dissect it, so don’t worry about copying code for a bit—I’ll let you know where we’re going to do that again. Let’s just focus on some key bits for now.
In JSX, you need to return a single element, which can have child elements. Because all of our code is wrapped in a
Inside the
{ self.state.name ?
Hello there. My name is { self.state.name }, and my favourite color is { self.getActiveColorName() }
: null }
This ternary operator checks to see if there’s a name set and renders either a sentence containing the name or null. Returning null in JSX is how you tell it to render nothing to the client. Also related to this snippet: we were able to run this ternary operator within our JSX because we created an expression by opening some brackets. It’s a really useful way of sprinkling small, simple bits of display logic within your render function.
Next up, let’s look at an event binding:
If you don’t bind an event to your input field, it’ll be read only. Don’t panic about forgetting though. React helpfully warns you in your console.
Remember, self is equal to this, so what we’re doing is attaching the updateName function to the input’s onChange event, but we’re also binding self, so that when we’re within the updateName function, this will equal AboutMe, which is our component.
The last thing we’re going to look at in the render function is loops. Here’s the snippet that renders the color menu:
The value and change setup is the same as the above element, so we’ll ignore them and dive straight in to the loop. What we’ve done is open up an expression where we run a pretty standard Array Map function, but, importantly, it returns JSX in each iteration, which allows each option to render with the rest of the JSX.
Wiring it all up
Now that we’ve got our core aspects of the component running, we need to wire it up. You’ll notice that your CodePen isn’t doing anything at the moment. That’s because of two things:
We haven’t attached the component to the DOM yet
We haven’t written any methods to make it interactive
Let’s start with the former and add our change event handlers. Add the following underneath your constructor function:
updateName(evt) {
let self = this;
self.setState({
name: evt.target.value
})
};
updateColor(evt) {
let self = this;
self.setState({
color: evt.target.value
})
};
These two functions handle the onChange events of the
ReactDOM is a really smart package that takes changes in your dynamic React components, calculates what needs to be changed in the DOM and applies those changes in the most efficient possible way. With ReactDOM’s renderToString() method, you can also render your React components to a static string, which can then be inserted to your page with your server-side code. What’s smart about this is that references are added so that if your front-end picks up some server-rendered React, it’ll work out which components are needed and make the whole chunk of static markup dynamic automatically. Pretty damn smart, huh?
Anyway, back to our Pen. Add this right at the bottom of your JS editor:
// Attach our component to the
ReactDOM.render(
Now, you’ll notice that your preview window has suddenly come alive! Congratulations — you just wrote a React component ?
See the Pen About Me React Component by Andy Bell (@hankchizlja) on CodePen.
Wrapping up
In this part, you’ve learned about reactive, component JavaScript by writing a React component. This is relevant to your learning because custom Gutenberg blocks follow a very similar setup to a React component. Now that you’ve got a better understanding of how a React component works, you should be able to understand how a custom Gutenberg block works too.
It took me a bit to wrap my mind around the fact that, in terms of Gutenberg, React is only relevant to building blocks within the admin. In Gutenberg, React functions as a means of preparing the markup to be saved to the database in the post_content column. Using React on the front-end of a WordPress site to build something like this would be separate from what we will be doing in this series.
Next up in this series, we’re going to edit our WordPress theme so that we can build our custom Gutenberg block.
Article Series:
Series Introduction
What is Gutenberg, Anyway?
A Primer with create-guten-block
Modern JavaScript Syntax
React 101 (This Post)
Setting up a Custom webpack
A Custom “Card” Block