{"id":271360,"date":"2018-05-23T12:41:57","date_gmt":"2018-05-23T19:41:57","guid":{"rendered":"http:\/\/css-tricks.com\/?p=271360"},"modified":"2018-05-25T07:43:08","modified_gmt":"2018-05-25T14:43:08","slug":"learning-gutenberg-5-react-101","status":"publish","type":"post","link":"https:\/\/css-tricks.com\/learning-gutenberg-5-react-101\/","title":{"rendered":"Learning Gutenberg: React 101"},"content":{"rendered":"

Although Gutenberg is put together with React<\/a>, the code we\u2019re writing to make custom blocks isn\u2019t. It certainly resembles a React component though, so I think it\u2019s useful to have a little play to get familiar with this sort of approach. There\u2019s been a lot of reading<\/em> in this series so far, so let\u2019s roll-up our sleeves and make<\/em> something cool.<\/p>\n

<\/p>\n

\n

Article Series:<\/h4>\n
    \n
  1. \n Series Introduction<\/a>\n <\/li>\n
  2. \n What is Gutenberg, Anyway?<\/a>\n <\/li>\n
  3. \n A Primer with create-guten-block<\/a>\n <\/li>\n
  4. \n Modern JavaScript Syntax<\/a>\n <\/li>\n
  5. \n React 101 (This Post)<\/em>\n <\/li>\n
  6. \n Setting up a Custom webpack<\/a>\n <\/li>\n
  7. \n A Custom “Card” Block<\/a>\n <\/li>\n<\/ol>\n<\/div>\n

    Let\u2019s make an \u201cAbout Me\u201d component<\/h3>\n

    We\u2019re 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. \u201cI thought this was supposed to be cool,\u201d<\/em> I hear you all mutter. I\u2019ll admit, I may have oversold it, but we\u2019re going to learn some core concepts of state-driven JavaScript<\/strong> which will come in handy when we dig into our Gutenberg block.<\/p>\n

    For reference, this is what we\u2019re going to end up with:<\/p>\n

    Getting started<\/h3>\n

    The first thing we\u2019re going to do is fire up CodePen<\/a>. CodePen can be used for free, so go head over there and create a new Pen<\/a>. <\/p>\n

    Next, we\u2019re going to pull in some JavaScript dependencies. There are three editor screens—find the JS<\/code> screen and click the settings cog. This will open up a Pen Settings modal where you\u2019ll find the section titled Add External Scripts\/Pens<\/strong>. Right at the bottom, theres a Quick-add<\/strong> select menu. Go ahead and open that up.<\/p>\n

    \"A<\/figure>\n

    From the menu, select React<\/strong>. Once that\u2019s selected, open the menu and select ReactDOM<\/strong>. You\u2019ll see that this has pre-filled some text boxes. <\/p>\n

    Lastly, we need to enable our ES6 code, so at the menu titled JavaScript Preprocessor<\/strong>, select Babel<\/strong>.<\/p>\n

    Now, go ahead and click the big Save & Close<\/strong> button. <\/p>\n

    What we\u2019ve 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.<\/p>\n

    Setup our CSS<\/h3>\n

    Let\u2019s make it look cool. First up though, let\u2019s setup our CSS editor. The first thing we\u2019re 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<\/strong> modal again—this time with the CSS settings.<\/p>\n

    At the top, there\u2019s a CSS Preprocessor<\/strong> menu. Go ahead and select SCSS<\/strong> from there. <\/p>\n

    When that\u2019s done, go down to the Add External Stylesheets\/Pens<\/strong> and paste the following three links into separate text-boxes:<\/p>\n

    https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/normalize\/8.0.0\/normalize.css\r\nhttps:\/\/fonts.googleapis.com\/css?family=Work+Sans:300\r\nhttps:\/\/rawgit.com\/hankchizljaw\/boilerform\/master\/dist\/css\/boilerform.min.css<\/code><\/pre>\n

    Those three in order give us a reset, a fancy font and some helpful form styles<\/a>.<\/p>\n

    Now that they\u2019re all set, go ahead and click the “Save & Close” button again. <\/p>\n

    Adding a bit of style<\/h3>\n

    We\u2019re all setup so this step should be easy. Paste the following Sass into the CSS editor:<\/p>\n

    :root {\r\n  --text-color: #f3f3f3;\r\n}\r\n\r\n* {\r\n  box-sizing: border-box;\r\n}\r\n\r\nhtml {\r\n  height: 100%;\r\n  font-size: 16px;\r\n}\r\n\r\nbody {\r\n  height: 100%;\r\n  position: relative;\r\n  font-size: 1rem;\r\n  line-height: 1.4;\r\n  font-family: \"Work Sans\", sans-serif;\r\n  font-weight: 300;\r\n  background: #f3f3f3;\r\n  color: #232323;\r\n}\r\n\r\n.about {\r\n  width: 100%;\r\n  height: 100%;\r\n  position: absolute;\r\n  top: 0;\r\n  left: 0;\r\n  color: var(--text-color);\r\n  transition: all 2000ms ease-in-out;\r\n  \r\n  &__inner {\r\n    display: flex;\r\n    flex-direction: column;\r\n    height: 100%;\r\n    margin: 0 auto;\r\n    padding: 1.2rem;\r\n  }\r\n  \r\n  &__content {\r\n    display: flex;\r\n    flex-direction: column;\r\n    justify-content: center;\r\n    align-items: center;\r\n    flex: 1 1 auto;\r\n    font-size: 3rem;\r\n    line-height: 1.2;\r\n    \r\n    > * {\r\n      max-width: 30ch;\r\n    }\r\n  }\r\n  \r\n  &__form {\r\n    display: flex;\r\n    flex-direction: column;\r\n    align-items: center;\r\n    padding: 2rem 0;\r\n    width: 100%;\r\n    max-width: 60rem;\r\n    margin: 0 auto;\r\n\r\n    @media(min-width: 32rem) {\r\n      flex-direction: row;\r\n      justify-content: space-between;\r\n      padding: 2rem;\r\n    }\r\n    \r\n    > * {\r\n      width: 15rem;\r\n    }\r\n    \r\n    > * + * {\r\n      margin: 1rem 0 0 0;\r\n      \r\n      @media(min-width: 32rem) {\r\n        margin: 0;\r\n      }\r\n    }\r\n    \r\n    label {\r\n      display: block;\r\n    }\r\n  }\r\n}\r\n\r\n\/\/ Boilerform overrides \r\n.c-select-field {\r\n  &,\r\n  &__menu {\r\n    width: 100%;\r\n  }\r\n}\r\n\r\n.c-input-field {\r\n  width: 100%;\r\n}\r\n\r\n.c-label {\r\n  color: var(--text-color);\r\n}<\/code><\/pre>\n

    That\u2019s a big ol\u2019 chunk of CSS, and it\u2019ll look like nothing has really happened, but it\u2019s all good—we\u2019re not going to have to worry about CSS for the rest of this section.<\/p>\n

    Digging into React<\/h3>\n

    The first thing we\u2019re going to do is give React something to latch on to. Paste this into the HTML editor of your Pen:<\/p>\n

    <div id=\"root\"><\/div><\/code><\/pre>\n

    That\u2019s it for HTML—you can go ahead and maximize your JS editor so we\u2019ve got complete focus. <\/p>\n

    Let\u2019s start our component code, by creating a new instance of a React component by writing the following JavaScript:<\/p>\n

    class AboutMe extends React.Component {\r\n}<\/code><\/pre>\n

    What that code is doing is creating a new AboutMe<\/code> component and extending React\u2019s Component<\/code> class, which gives us a load of code and tooling for free. <\/p>\n

    Right, so we\u2019ve got a class, and now we need to construct it! Add the following code, inside the brackets:<\/p>\n

    constructor(props) {\r\n  super(props);\r\n  \r\n  let self = this;\r\n};<\/code><\/pre>\n

    We\u2019ve got a few things going on here, so I\u2019ll explain each:<\/p>\n

    constructor<\/code> is the method that\u2019s called when you write new AboutMe()<\/code>, or if you write <AboutMe \/><\/code> in your JSX. This constructs the object. The props<\/code> parameter is something you\u2019ll see a lot in React. This is the collection of properties that are passed into the component. For example: if you wrote <AboutMe name=\"Andy\" \/><\/code>, you\u2019d be able to access it in your constructor<\/code> with props.name<\/code>.<\/p>\n

    super<\/code> is how we tell the class that we\u2019ve extended to construct with its own constructor<\/code>. You\u2019ll see we\u2019re also passing the props<\/code> up to it in case any parent components need to access them.<\/p>\n

    Finally let self = this<\/code> is a way of controlling the scope of this<\/code>. Remember, because we\u2019re using let<\/code>, self<\/code> will only be available in the constructor<\/code> function.<\/p>\n

    Quick note for those readers not-so-confident in JavaScript: I found a deeper look at scope<\/strong> in JavaScript to result in a lot of \u201caha\u201d moments in my learning. I highly recommend Kyle Simpson<\/a>\u2019s You Don\u2019t Know JS<\/em> book series (available for free on GitHub<\/a>!). Volumes of note: this<\/code> and Object Prototypes<\/a> and Scope & Closures<\/a>. Good stuff, I promise.<\/div>\n

    Now we\u2019ve covered the constructor, let\u2019s add some more code to it. After the let self = this;<\/code> line, paste the following code:<\/p>\n

    self.availableColors = [\r\n  {\r\n    \"name\": \"Red\",\r\n    \"value\": \"#ca3814\"\r\n  },\r\n  {\r\n    \"name\": \"Blue\",\r\n    \"value\": \"#0086cc\"\r\n  },\r\n  {\r\n    \"name\": \"Green\",\r\n    \"value\": \"#3aa22b\"\r\n  }\r\n];<\/code><\/pre>\n

    What we\u2019ve got there is an array of objects that define our options for picking your favorite color. Go ahead and add your own if it\u2019s not already there! <\/p>\n

    Your class definition and constructor should now look like this: <\/p>\n

    class AboutMe extends React.Component {\r\n  \r\n  constructor(props) {\r\n    super(props);\r\n    \r\n    let self = this;\r\n    \r\n    \/\/ Set a list of available colors that render in the select menu\r\n    self.availableColors = [\r\n      {\r\n        \"name\": \"Red\",\r\n        \"value\": \"#ca3814\"\r\n      },\r\n      {\r\n        \"name\": \"Blue\",\r\n        \"value\": \"#0086cc\"\r\n      },\r\n      {\r\n        \"name\": \"Green\",\r\n        \"value\": \"#3aa22b\"\r\n      }\r\n    ];\r\n  };\r\n}<\/code><\/pre>\n

    Pretty straightforward so far, right? Let\u2019s move on and set some initial values to our reactive state. Add the following after the closing of self.availableColors<\/code>:<\/p>\n

    \/\/ Set our initial reactive state values\r\nself.state = {\r\n  name: 'Foo',\r\n  color: self.availableColors[0].value\r\n};<\/code><\/pre>\n

    This initial setting of state enables our component to render both a name and a color on load, which prevents it from looking broken.<\/p>\n

    Next, we\u2019ll add our render<\/code> 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\u2019s lifecycle<\/a>. You may have guessed already, but this is where the main body of our JSX lives.<\/p>\n

    Wait up! What\u2019s a pure function<\/em>? Welcome to functional programming, a hot topic in the React world. Pure<\/em> 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\u2019s a CodePen<\/a> comparing pure and impure functions. Check out this article<\/a> out, too, for more details.<\/div>\n

    Now, because there\u2019s quite a lot of markup in this single component, we\u2019re going to copy the whole lot into our function. Add the following under your constructor<\/code>:<\/p>\n

    render() {\r\n  let self = this;\r\n  \r\n  return (\r\n    <main className=\"about\" style={ { background: self.state.color } }>\r\n      <section className=\"about__inner\">\r\n        <article className=\"about__content\">\r\n          { self.state.name ? <p>Hello there. My name is { self.state.name }, and my favourite color is { self.getActiveColorName() }<\/p> : null }\r\n        <\/article>\r\n        <form className=\"[ about__form ] [ boilerform ]\">\r\n          <div>\r\n            <label className=\"c-label\" htmlFor=\"name_field\">Your name<\/label>\r\n            <input className=\"c-input-field\" type=\"text\" id=\"name_field\" value={ self.state.name } onChange={ self.updateName.bind(self) } \/>\r\n          <\/div>\r\n          <div>\r\n            <label className=\"c-label\" htmlFor=\"color_field\">Your favourite color<\/label>\r\n            <div className=\"c-select-field\">\r\n              <select className=\"c-select-field__menu\" value={ self.state.color } onChange={ self.updateColor.bind(self) } id=\"color_field\">\r\n                { self.availableColors.map((color, index) => {\r\n                  return (\r\n                    <option key={ index } value={ color.value }>{ color.name }<\/option>\r\n                  );\r\n                })}\r\n              <\/select>\r\n              <span className=\"c-select-field__decor\" aria-hidden=\"true\" role=\"presentation\">\u25be<\/span>\r\n            <\/div>\r\n          <\/div>\r\n        <\/form>\r\n      <\/section>\r\n    <\/main>\r\n  );\r\n};<\/code><\/pre>\n

    You may be thinking something like: \u201cHoly cow, there\u2019s a lot going on here.\u201d Let\u2019s dissect it, so don\u2019t worry about copying code for a bit—I\u2019ll let you know where we\u2019re going to do that again. Let\u2019s just focus on some key bits for now.<\/p>\n

    In JSX, you need to return a single element, which can have child elements. Because all of our code is wrapped in a <main><\/code> tag, we\u2019re all good there. On that <main><\/code> tag, you\u2019ll see we have an expression in an attribute, like we covered in Part 2<\/a>. This expression sets the background color as the current active color that\u2019s set in our state. This will update like magic when a user changes their color choice without us having to write another line of code for it in this render function. Pretty cool, huh? <\/p>\n

    Inside the <article class=\"about__content\"><\/code> element, you\u2019ll notice this: <\/p>\n

    { self.state.name ? <p>Hello there. My name is { self.state.name }, and my favourite color is { self.getActiveColorName() }<\/p> : null }<\/code><\/pre>\n

    This ternary operator<\/a> checks to see if there\u2019s a name set and renders either a sentence containing the name or null<\/code>. Returning null<\/code> 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\u2019s a really useful way of sprinkling small, simple bits of display logic within your render<\/code> function.<\/p>\n

    Next up, let\u2019s look at an event binding: <\/p>\n

    <input className=\"c-input-field\" type=\"text\" id=\"name_field\" value={ self.state.name } onChange={ self.updateName.bind(self) } \/><\/code><\/pre>\n

    If you don\u2019t bind an event to your input field, it\u2019ll be read only. Don\u2019t panic about forgetting though. React helpfully warns you in your console.<\/p>\n

    Remember, self<\/code> is equal to this<\/code>, so what we\u2019re doing is attaching the updateName<\/code> function to the input\u2019s onChange<\/code> event, but we\u2019re also binding self<\/code>, so that when we\u2019re within the updateName<\/code> function, this<\/code> will equal AboutMe<\/code>, which is our component.<\/p>\n

    The last thing we\u2019re going to look at in the render<\/code> function is loops. Here\u2019s the snippet that renders the color menu:<\/p>\n

    <select className=\"c-select-field__menu\" value={ self.state.color } onChange={ self.updateColor.bind(self) } id=\"color_field\">\r\n  { self.availableColors.map((color, index) => {\r\n    return (\r\n      <option key={ index } value={ color.value }>{ color.name }<\/option>\r\n    );\r\n  }) }\r\n<\/select><\/code><\/pre>\n

    The value and change setup is the same as the above <input \/><\/code> element, so we\u2019ll ignore them and dive straight in to the loop. What we\u2019ve done is open up an expression where we run a pretty standard Array Map function<\/a>, but, importantly, it returns JSX in each iteration, which allows each option to render with the rest of the JSX.<\/p>\n

    Wiring it all up<\/h3>\n

    Now that we\u2019ve got our core aspects of the component running, we need to wire it up. You\u2019ll notice that your CodePen isn\u2019t doing anything at the moment. That\u2019s because of two things:<\/p>\n