
Creating a React Component
Now that we have a strong grasp of JSX and React, we have everything that we need to be able to start building out our own React components. We now need to cover the work of actually writing a component. When creating new components in React, you have a few options that are commonly used, and they each serve slightly different purposes.
Sometimes you need a small, lightweight declaration of a component to just display something simply and easily where you are not worried about a lot of state modification or user interaction. The easiest way to declare a component in React is with functional syntax.
Preparing Our Code to Start Writing Our Component
Remember that when creating a new project with create-react-app, we start off with a bunch of starter components and a lot of extra code pre-written for us. The best course for us is to wipe out the starter Create React App code and begin rewriting it with our own component. We will start off with a simple functional component and then move on to the class syntax for declaring more complex components. Let's take a look at the list of all of the files that we get in src/ when we create a new app:
src/
App.css
App.js
App.test.js
index.css
index.js
logo.svg
serviceWorker.js
setupTests.js
This is all great, but there is a lot of code in these that we don't really need, and it will make our lives a little easier to keep things managed if we start clearing things out. We do not quite want to delete everything since some of the boilerplate code is actually pretty useful, but some of the files we also very much don't need.
First off, delete src/logo.svg, since we don't need that file at all anymore. We will leave src/index.css and src/index.js alone, as well as src/serviceWorker.js. Anything outside of src We will just leave alone as well. You will also want to remove any references to the files you deleted, like src/logo.svg, from src/App.js.
The next step is for us to delete the CSS file for the App component: src/App.css since we are not going to use it.
Understanding Props
Props is just a shorthand name for properties, and you can think of them similarly to how you will think about passing in HTML attributes to modify the behavior of an HTML tag. Passing in props allows components to take in information along the way and change how the component is rendered to the end user.
An example of passing props to a component is moving the Greeting from the code snippet used in Exercise 1.01, Implementing JSX into its own component and then including that in our base App component:
<p
className="greeting"
style={{ background: "black", color: "white" }}
>
We will declare this new Greeting component in the same src/App.js file, and then we will pass down a name prop to the Greeting component. In our Greeting component, we will have it display the Hello React message from before, but we will replace the React message with the passed-in name prop. Let's see an example of how to implement props in React.
First, the code for our Greeting component will change to this:
const Greeting = props => <p>Hello {props.name}!</p>;
Next, we will need to use this new component in our App component and pass the new props down. Let's head back to our previous multiline component and modify it to instead call the Greeting component and pass a name prop:
const App = props => (
<p>
<h1>My App</h1>
<br />
<Greeting name="User" />
</p>
);
Now, save and reload your app (which usually happens automatically), and you should see this:

Figure 1.7: First React component created
Let's explore props with an exercise.
Exercise 1.02: Creating Our First React Component
In this exercise, we will clean up the src/App.js file. We will follow a similar path as mentioned in Exercise 1.01, Implementing JSX by opening up src/App.js and replacing its contents with the component we will be building in this exercise:
- Add an import statement and an export statement to the top and bottom of the file, respectively, to include the React library and export the component (named App, like the filename) as the default export:
import React from 'react';
export default App;
There are a few things here we need to talk about before we start building out the component in full, though.
First off, we need to import the React library into our file so that we can actually start building out our component. Without this statement, the rest of the component building would fail as JavaScript and Node.js would have no idea how to interpret the code.
The next line will end up actually being the last line of our code file; this allows JavaScript to import code in this file into other files in a clean way. We have not actually created the app that we are exporting, but don't worry about that. We will have that built in just a minute.
- Next, we will want to build out the initial component. This will start off very simple and should just be a p with the text Hello React! in it:
import React from 'react';
const App = () => <p>Hello React!</p>;
export default App;
As mentioned back at the start, there is a lightweight method of declaring your components in React, and that will be the strategy that we use to start writing this all out. Declaring a functional component in React is incredibly simple since it is just a function declaration that returns some JSX. In fact, when we get right down to it, there is not really any other major difference. So, in our code, we are going to create a new function called App, and we are going to have it return a p with some Hello React code in it.
We will have a component that looks like this when the browser refreshes:
Figure 1.8: Simple component in React
By default, this gives us a pretty basic component with no frills, and if you are aiming to just create a quick and easy component used to display something, this is probably what you would use. There is also an option to pass in props to functional components by passing them in as a function argument, which would change our function to this.
- Let's write the following code:
const App = props => <p>Hello React!</p>;
This would allow you to use this with a parent component, for example, that is passing details down to a child (but we will talk about that a little more later). You can also use standard function syntax if you prefer that.
This is the ES6 arrow function syntax:
const App = props => <p>Hello React!</p>
and it becomes:
function App(props) {
return <p>Hello React!</p>;
}
The arrow syntax is much cleaner and is more preferable. In addition, if you have a component that spans multiple lines, you will need to wrap your JSX inside parentheses instead.
- Let's expand our component from the previous example and add an h1 header to the app, in addition to our Hello React! message:
import React from 'react';
const App = props => (
<p>
<h1>My App</h1>
<br />
Hello React!
</p>
);
export default App;
The resulting component should look like this:
Figure 1.9: React component
With all this knowledge, let's move onto the next section.
Understanding React Rendering
We have created two separate React components here but only with a cursory understanding of what is happening behind the scenes, so it's worth spending a little time unpacking what is happening in these functional components, especially in relation to the concept of rendering in React.
The reason that just returning JSX in a functional component works is that ultimately, anything returned by a function is a valid target for React to render if it is called from React code. It is pretty easy to see in the Greeting function how this plays out: when you use the JSX tag for a function, it basically turns whatever the function returns into usable JSX code. If we return JSX in our function, then it all gets rendered appropriately.
Let's also explore what happens higher up in the React call stack when rendering is involved. It's one thing to understand rendering at the level of the components we write, but we should also understand how those get from the code we write to the actual browser page.
Back in src/index.js, one of the files that we did not modify, if you look through it, you will see a call to ReactDOM.render():
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
ReactDOM is a library that provides interaction with the DOM layer of the browser, and we use it specifically to place our React components into the browsers, available to be viewed and interacted with by the user.
In this case, we are taking our App component, represented by the JSX code <App />, and we are rendering the output of that (which must be valid JSX code) to the browser, converting everything from JSX into code the browser can understand and interpret.
This is why our functional component needs to return JSX, and why (as you will see later) our class-based components need to return JSX in their render function calls. If we return something JSX cannot interpret, then we will get an error message instead.
Verify the results of the preceding statement by changing the Greeting function to instead return anything else that's non-JSX and verify what happens for each.
Note
StrictMode helps to spot potential errors in advance. It performs code checks only during development time. It does not work in the production run.
Building Components with Classes
You can build your components using functional syntax, but there is another way to declare your React components that allows better state management in your components. You will be introduced to the basics of using classes. This topic will be covered in more detail in the later chapters.
In addition, the functional components of React have no real sense of utility functions or internal state; everything must be represented via props or not at all.
Instead, let's shift our focus to the other common method of building out React components: using classes. We will want to add one more addition to our React import statement at the top of our file because not only do we now want to import React, but we would also like to include the Component class from the React import.
Exercise 1.03: Implementing a Click Counter in React Using Classes
In this exercise, we will create a click counter for a web page. Here, we will convert the component we built previously as a functional component into a class component. Perform the following steps:
- First, change the import statement to also include Component from the React library.
We can import both at the same time with the following line:
import React, { Component } from 'react';
This tells us that we are going to import the React library as a whole, but that we also specifically want to pull Component out from the named exports.
This gives us everything we need to start modifying our App component to instead be a class-based component. We will start off by writing out the class definition and then build it up as we go along.
- Next, convert the functional declaration of the component to a class declaration that extends the Component import:
class App extends Component {
}
Here, we define what was previously our functional App component as a class-based component (still called App).
The next bit of this uses that Component named import that we specified at the top of the file. The extends keyword here tells JavaScript that our App component has a parent class, Component, and that its behavior should act as an extension to that parent class.
- Next, add a render function, since we can't just return JSX in a class directly, and include what used to be the body of the component before:
render() {
return (
<p>
<h1>My App</h1>
<br />
<Greeting name="User" />
</p>
);
}
This is mostly identical to our functional component, with the addition of needing to specifically declare the render function itself (without this, React doesn't know how specifically to deal with this class and render it out appropriately via JSX). We also need an explicit return statement since we are not using arrow syntax here, but otherwise this function remains identical.
Now, what if we wanted to go deeper? As mentioned previously, a critical reason to use this style of component declaration is the ability to manage state, and if you look at our render function, we are also missing any references to props.
The easiest way to define our class component in a way that allows us access to both state and props is to define a constructor function. The constructor function acts as the way for JavaScript to instantiate our new class (turn it from a class definition into an object) and set up any sort of default or initial values or state that we may need to think about.
- Define this by creating a new function in our class called constructor and pass a props argument. You will also need to include a call to the constructor via super and pass in the props argument:
constructor(props) {
super(props);
}
We can flesh this out even further. For example, maybe your class has some sort of code-configurable option to it that you do not necessarily want to expose to the user as part of its state.
- In the constructor function, let's add a new variable to the object that will keep track of the title of the app:
this.title = 'React App';
- Now change the render() function so that the header displays the value we just set instead of the hard-coded My App:
<h1>{this.title}</h1>
Finally, let's set up some internal state for our object. Do not worry too much about some of the specifics here (such as the onClick handler), as We will be going into these in much greater detail in later chapters.
We will start off by describing what it is that we want our component to do. In our case, we want to keep track of the number of times a particular button is clicked, and we want to display that count to the user.
Note
The button does not exist in the code. The clickCounter has been hard-coded.
- Start off by adding an initial state declaration into our constructor function:
this.state = { clickCounter: 0 };
- Next, use a helper function to render the click count display to the user.
As mentioned previously, React and JSX can handle rendering any function that returns JSX. That means that writing helper methods inside a class is an incredibly simple thing to do.
renderClickCount() {
return <p>I've been clicked {this.state.clickCounter} times!</p>;
}
The even better news is that adding this display to our component is a simple matter of calling the function inside curly braces in our JSX.
- Add these lines beneath the Greeting line in our render function:
<br />
{this.renderClickCount()}
If you were following along, the final state of our code for the src/App.js function should look something like this:
App.js
3 const Greeting = props => <p>Hello {props.name}!</p>;
4
5 class App extends Component {
6 constructor(props) {
7 super(props);
8 this.title = 'React App';
9 this.state = { clickCounter: 0 };
10 }
The complete code can be found here: https://packt.live/2WsVTkA
The final display of the component should look like this:

Figure 1.10: Click counter in a React component
With a firm grasp of the fundamentals of bootstrapping your first project in React, let's expand this and build a new project. Your project will allow you to demonstrate the early skills you have learned so far and put them into action while building a practical React example.
Activity 1.01: Design a React Component
Let's say we want to start building a new e-commerce site, and we need to start off by building a skeleton for the main store page. We will call our project buystuff. In this project, you'll need to create a new project, create a header React component, create an inventory template React component, and then put everything together in our main React application project.
The following steps will help you to achieve the goal:
- Verify that Node.js and Create React App are installed on your machine.
- Create your project, called buystuff, via the Create React App CLI.
- Delete all of the unnecessary files for our project.
- Build the App React component as a class component but leave it blank.
- Build the Header React component as a functional component. Its only prop should be title, which contains the store's name.
- Build the InventoryItem React component as a functional component. It should contain props that consist of the item name and price.
- Change the App component to have a constructor and a starting state with two items in it, and include your InventoryItem component in the render() function twice and your Header component once.
The end result should give us a React application that looks like this:

Figure 1.11: BuyStuff React component
Note
The solution of this activity can be found on page 606.