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 therender
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")
)
);
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>
...
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 />;
}
to
renderSquare(i) {
return <Square value={i} />
}
and change
{/* TO-DO */}
to
{this.props.value}
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'); }}
...becomes...
onClick={() => alert('click')}
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')}
...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
};
}
}
Two things here:
- this
Square
class is clearly calling the constructor of the parent class (React.Component
) withsuper()
, passing theprops
to the parent class constructor. - 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 aconstructor
should start it with asuper(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')}
changes to
onClick={() => this.setState({value: 'X'})}
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 onClick
s 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!