Learning React With Create-React-App (Part 2)

Brandon Richey
In the weeds
Published in
8 min readAug 10, 2016

Last Updated: 11/17/2017

Let me ask you this: why NOT a goat?

Previous Post In This Series

Current Versions

create-react-app: v1.4.3

react: v16.1.1

react-scripts: v1.0.17

Introduction

In the last tutorial, we got started with create-react-app and started learning React at a very basic level. The idea is to jump into React development without a lot of the setup concerns that would be necessary to get Webpack/Babel/etc ready for development. We also jumped into development and started building out our first React component. Now that we have our base and understand a little ES2015 and React code, let’s start improving our code and making things more interactive!

Separating Out Our Hello World Component

Our App component should remain a little more specialized and exist really only to contain our application itself, so let’s create two new files: src/HelloWorld.js and src/HelloWorld.css.

In src/HelloWorld.js, just copy over everything from App.js but rename the function and the className:

import React from 'react';
import './HelloWorld.css';

const HelloWorld = () => {
return (<div className="HelloWorld">Hello World!</div>);
};

export default HelloWorld;

There’s nothing new here, so we’ll leave it be. We’ll do the same thing with src/HelloWorld.css:

.HelloWorld {
border: 2px solid black;
text-align: center;
background: #f5f5f5;
color: #333;
margin: 20px;
padding: 20px;
}

Our src/App.css file should now be blank. Now, let’s head back to src/App.js and start making modifications. The first thing we need to do is import our new HelloWorld.js component into App.js:

import HelloWorld from './HelloWorld';

And then we’re going to change the component itself to include our HelloWorld component as a JSX tag:

const App = () => {
return (
<div className="App">
<HelloWorld/>
</div>
);
};

So we still have our root div in our component, which then renders a child HelloWorld component! Save and reload and we should see the same screen as before! The neat thing about extracting out our HelloWorld component is that now we could easily include multiple HelloWorld components without much more work than copying/pasting a single line of code! In fact, let’s do that now! Back in src/App.js:

const App = () => {
return (
<div className="App">
<HelloWorld/>
<HelloWorld/>
</div>
);
};

Notice that we have <HelloWorld/> declared twice inside of our root div. Save the file and reload and you should see:

A huge amount of reusability with very, very little effort!

But what if we want to start introducing some variation to our components so that they don’t just say “Hello World”? What if instead we want it to display two different names? Enter props!

Introducing Props

props are essentially just properties inside of a React component that are passed in from somewhere (generally the parent). The functional component that we’re using here right now (HelloWorld) doesn’t accept any arguments to its function, so let’s change that. Open up src/HelloWorld.js and make the following modifications. First, in the declaration for the function, add a single argument called “props”:

const HelloWorld = props => {

This is the equivalent of us writing:

function HelloWorld(props) {

Next, inside of the return statement, change “World” to instead be {props.name}:

return (<div className="HelloWorld">Hello {props.name}!</div>);

Save the file, and return back to src/App.js. Now we need to actually pass in this “name” property to the HelloWorld component!

const App = () => {
return (
<div className="App">
<HelloWorld name="Jim"/>
<HelloWorld name="Sally"/>
</div>
);
};

Save this file and the auto-reload should give us a page that looks like this:

Reusable, modifiable components!

Any changes to props for a component triggers that component into re-rendering depending on what changed and where. This is pretty neat, overall, especially when you factor in how little effort really went into making this all work! However, when we want to introduce some real interaction, we will likely want to shy away from using props and instead introduce a new concept, state. But before we can even do that, we need to change how our HelloWorld component is declared. Functional components are great for things that don’t really require any concept of dynamic modifications or interaction, but if want to start tracking those and responding to them appropriately, we need to start taking advantage of state, and to do that, we’ll need ES2015 Class-based components!

Introducing Class Components

First, we need to change our import in src/HelloWorld.js. Previously, our import from React looked like this:

import React from 'react';

This imports whatever the default export is from the ‘react’ NPM module as “React”, but we also need a specific named export from the react module as well: Component. Based on that, our import statement should be changed to:

import React, { Component } from 'react';

Now we have access to the Component class, so we can start modifying our initial component:

class HelloWorld extends Component {
render() {
return (
<div className="HelloWorld">Hello {this.props.name}!</div>
);
}
}

So first, we declare a new ES2015 class via the class keyword. We still call it HelloWorld, but we need to explicitly tell Javascript that our HelloWorld component extends the functionality of the Component class!

Next, any class component in React needs to have a render() function that returns out our JSX. So, we define render() { … }, the contents of which are just what used to be our functional component with one major difference: props.name becomes this.props.name! “props” is no longer passed in; it is now accessible only as a property on the HelloWorld object itself, so we need to use this.props to tell Javascript that the component’s properties live inside of the class! Now we can go really crazy and start maintaining a concept of internal state!

And Now Introducing State

Before we can start dealing with our internal state in our component, we need to set up an initial state. To do that, we’ll need to implement a constructor for our class (a function that is called when the class is used anywhere). In the HelloWorld class, implement a constructor function that should take in props as the only argument:

constructor(props) {
super(props);
this.state = { greeting: 'Hello' };
}

constructor() is a special function that ES2015 functions rely on to perform some actions when the class is used (usually referred to as “instantiation”). As I mentioned previously, it needs to accept a “props” argument. It also needs to call out to its parent constructor, which it does via the call to super(props). This calls the parent’s constructor (which since it is a Component too is also expecting props passed to it). Then, we set a property on the class called “state” via the this.state declaration. We set it to a base object that contains a single property called “greeting” which has a default value of “Hello”. Now we’ll need to modify our render function to use the greeting value out of state:

render() {
return (
<div className="HelloWorld">
{this.state.greeting} {this.props.name}!
</div>
);
}

Save your file and reload it and you should still see the same thing! Pretty cool, but now we really need a concept of interactivity to really make this example pop!

Adding Interactivity Via State Modifications

Let’s add a button to our HelloWorld component called “Frenchify”. Its job will be to change the default greeting from “Hello” to “Bonjour!” We want to make sure that any of these modifications are local to that component only and do not affect every component. To do this, we need to start off by modifying our render function again to include our “frenchify” button!

render() {
return (
<div className="HelloWorld">
{this.state.greeting} {this.props.name}!
<br/>
<button onClick={this.frenchify}>Frenchify!</button>
</div>
);
}

We specify an onClick event handler in our button that calls a frenchify function defined on our class (that we haven’t written yet, don’t worry!). Otherwise, this component remains the same! Next, let’s write frenchify:

frenchify() {
this.setState({ greeting: 'Bonjour' });
}

So, here’s an interesting gotcha. You cannot modify the state object inside of a class directly. Instead, any state changes NEED to happen via the this.setState function. setState only changes keys that are specified inside of the state; it does not replace the entire state. Now, if we save this and try to click the “frenchify” button directly, we’ll actually get an error message to start:

Yikes!

“TypeError: this is undefined”? Wait, what? What is undefined?” you may be saying to yourself! This is another gotcha of using ES2015 classes with React components: any events that need to access any internal object details need to be explicitly bound to that instance of that component! In simpler terms, that means that “this.frenchify” doesn’t really know how to call “this.setState”, because it doesn’t understand what this is supposed to refer to. To fix this, we’ll jump into our constructor and add one more line:

this.frenchify = this.frenchify.bind(this);

This tells Javascript “Hey, any time you see a reference to this inside of the frenchify function, I want you specifically to refer to ME.” Now save the file and go back to your browser and click one of the “frenchify” buttons and you should see the greeting for ONLY that component changed to “Bonjour” from “Hello”! Fantastic!

Properly frenchified!

Conclusion

We now have isolated state per each component, components that are reusable and configurable per instance, interactivity, and more idiomatic separation of components! This is a pretty big step towards understanding how to write more complex React components and in general makes for a very happy development process!

In future tutorials, we’ll start diving a little more into reusability and introduce some new things like rendering lists of components from functions and working with lifecycle methods inside of React components such as componentWillMount, componentDidMount, etc!

Next Post in this Series

Check out my new books!

Hey everyone! If you liked what you read here and want to learn more with me, check out my new book on using the latest version of Create React App:

This covers everything you need to know to become proficient using Create React App v2 to become a better, more productive front-end developer, and really dive deep into the details of Create React App all while building a new React project from scratch!

And, of course, my Phoenix Web Development book is also still available if you want to learn more about Elixir web development:

I’m really excited to finally be bringing this project to the world! It’s written in the same style as my other tutorials where we will be building the scaffold of a full project from start to finish, even covering some of the trickier topics like file uploads, Twitter/Google OAuth logins, and APIs!

--

--