An Absolute Beginner Learns React, Part II

Andrew (he/him) - Apr 3 '19 - - Dev Community

In my last stream-of-consciousness blog post on learning React from scratch, I began working my way through ReactJS.org's tutorial. I built my first app by copying-and-pasting code... but it worked! Today, I hope to understand a bit of the code that I ran. Let's get started.


This bit I think I understand. React.Component is a basic component class, and we create a ShoppingList class that extends it. I'm guessing that components are required to have a render() method, which returns some HTML element(s) to render. This one creates a <div> with a className attribute -- is this similar to the HTML class attribute? -- which contains a header (<h1>) and an unordered list (<ul>) of all the companies Mark wants to buy.

this.props.name, I would guess, accesses the props variable of this, which I suppose refers to that instance of the ShoppingList class. It accesses name, which is defined in the XML-like tag in the example. If you can arbitrarily define properties like that, this syntax is pretty cool. What if we don't pass a name to ShoppingList, though? Does the code throw an error? Or just render nothing where {this.props.name} should be?

"When our data changes, React will efficiently update and re-render our components."

So it's a reactive programming framework, like I thought. That makes sense, given its name.

"Here, ShoppingList is a React component class, or React component type. A component takes in parameters, called props (short for “properties”), and returns a hierarchy of views to display via the render method."

That's more or less what I thought, but I don't understand what "hierarchy of views" means. The tutorial says that that block of code above, which looks mostly like HTML, can also be written as:

React.createElement("div", { className: "shopping-list" },
  React.createElement("h1", null, "Shopping List for ", props.name),
  React.createElement("ul", null,
    React.createElement("li", null, "Instagram"),
    React.createElement("li", null, "WhatsApp"),
    React.createElement("li", null, "Oculus")
  )
 );
Enter fullscreen mode Exit fullscreen mode

This sort of reminds me of the difference between JavaFX with and without FXML. When building a Java GUI with FXML, the markup is more XML-like. Without it, it looks much more like the block of code just above, where functions and properties are accessed using the dot (.) operator.

"createElement is described in more detail in the API reference", the tutorial says, so I click on that link, hoping to find some decently documented code:

The documentation looks really nice. Pretty easy to follow and understand. I thnik [props] is a list of properties? When we used it in the code block above, though, we sent the second argument to createElement in curly braces ({className: 'shopping-list'}). The variadic list of [...children] isn't surrounded in braces when we pass it to createElement, though... I'm a bit confused here. Maybe there are two kinds of lists? Maybe one's a list and one's a dictionary (or a map)?

That's pretty neat. So we can build up an app piece-by-piece from small components, using them within larger ones. The next step is to inspect the JavaScript code that I copied-and-pasted in my last entry:

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';

class Square extends React.Component {
  render() {
    return (
      <button className="square">
        {/* TODO */}
      </button>
    );
  }
}

class Board extends React.Component {
  renderSquare(i) {
    return <Square />;
  }

  render() {
    const status = 'Next player: X';

    return (
      <div>
      ...
Enter fullscreen mode Exit fullscreen mode

It looks pretty self-explanatory. As the tutorial notes, we have a Square class and a Board class that renders nine squares for the tic-tac-toe game. Some things are left undone for me to code, I'm guessing.

...that's right. The next step is to fill in two small things, we change

  renderSquare(i) {
    return <Square />;
  }
Enter fullscreen mode Exit fullscreen mode

to

  renderSquare(i) {
    return <Square value={i} />
  }
Enter fullscreen mode Exit fullscreen mode

and change

        {/* TO-DO */}
Enter fullscreen mode Exit fullscreen mode

to

        {this.props.value}
Enter fullscreen mode Exit fullscreen mode

This passes the "value" of the square to be rendered on the button. I change this code and run npm start again. And again it takes an extremely long time to render. But it does work...

...so that's something.

Congratulations! You’ve just “passed a prop” from a parent Board component to a child Square component. Passing props is how information flows in React apps, from parents to children.

The next thing we do is add an onClick method to the button in Square, which opens a JavaScript alert() box. I've seen these sorts of things before with the JavaScript experience I had a few years ago, so they're not very difficult for me.

The next thing we do is replace that onClick function with an "arrow function", as they're apparently called in JavaScript. I think most other programming languages refer to them as "lambda functions":

onClick={function() { alert('click'); }}
Enter fullscreen mode Exit fullscreen mode

...becomes...

onClick={() => alert('click')}
Enter fullscreen mode Exit fullscreen mode

That saves a little bit of typing. The tutorial makes sure to note that we need to pass a function to onClick. If we only wrote...

onClick={alert('click')}
Enter fullscreen mode Exit fullscreen mode

...then the alert would fire every time the component re-renders. Which is presumably not what we want.

Next, we add state to the Square class so it can "remember" whether or not it's been clicked. This is similar to instance / member variables in most OOP languages, I think. It looks like we can set a React object's state in a constructor function within the class definition:

class Square extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: null
    };
  }
}
Enter fullscreen mode Exit fullscreen mode

Two things here:

  1. this Square class is clearly calling the constructor of the parent class (React.Component) with super(), passing the props to the parent class constructor.
  2. the tutorial actually has a comma after the null, which I am assuming is a typo

In JavaScript classes, you need to always call super when defining the constructor of a subclass. All React component classes that have a constructor should start it with a super(props) call.

It looks like super(props) is mandatory in the constructor of any subclass. I wonder if it must be the first line of the constructor, like in Java...? The excerpt above is sort of ambiguous about that.

We then change the onClick of the button to change the state of the button, using setState(), which seems easy enough.

onClick={() => alert('click')}
Enter fullscreen mode Exit fullscreen mode

changes to

onClick={() => this.setState({value: 'X'})}
Enter fullscreen mode Exit fullscreen mode

When you call setState in a component, React automatically updates the child components inside of it too.

This sounds like a reactive dependency. If an object updates and other objects depend on it, then those dependent objects are updated, as well.

The very last thing I do is install the React Developer Tools Chrome extension, so I can inspect my React code in the browser:

Nice!


Well, I'm definitely starting to understand how React works. Seeing familiar things like classes and constructors and lambda functions makes me more confident that this is something I'll be able to pick up pretty easily. So far, I've basically just been making onClicks on steroids, so I hope there's more I can do with this framework. I'm looking forward to making some cool interactive web pages!

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .