Understanding the Fundamentals of State in React
Cover Image by Edmond Atto
Recap:
- In Chapter One, get introduced to React with ES6. If you are new to React , simply need a refresher, or need a gentle introduction to the ES6 features that are most frequently used throughout this book, review chapter one.
- In Chapter Two, get introduced to React components. They are the building blocks of any React Application you will build. Go ahead and review that chapter if you are not yet comfortable with React components and then head back here.
In earlier chapters, we’ve dealt mostly with functional React components that do not require state management. This chapter’s main focus is on state, its management and components that utilise it in React.
What is State?
State is a JavaScript object that stores a component’s dynamic data and determines the component’s behaviour. Because state is dynamic, it enables a component to keep track of changing information in between renders and for it to be dynamic and interactive.
State can only be used within a class component. If you anticipate that a component will need to manage state, it should be created as a class component and not a functional one.
State is similar to props
but unlike props
, it is private to a component and is controlled solely by the said component. In the examples from previous chapters, the behaviour of components has primarily depended on the props
that are passed down to them. In those cases, the components that receive the props have no control over them because props are read-only.
In Project One from Chapter 2, toys
were passed as props
to the Application
component, and then down to the Toys
component. For the Toys
component to gain control over the toys
data, it should first be converted into a class component and the toys
data should be added into state
.
It is worth mentioning that state in React is immutable, that is to say, state should never be altered/changed directly but rather, changes should be made to a copy of the current version of the state. This has benefits such as providing the ability to review the state at different points in time and for apps to hot reload (automatic reloading of the page in the browser when you make changes in the code).
Adding State to a Class Component
class Greeting extends React.Component {
render(){
return <h1>I’m a component in need of some state!</h1>;
}
}
Adding state to the Greeting
component above involves defining within the class component, a constructor function that assigns the initial state using this.state
.
class Greeting extends React.Component {
constructor(props) {
super(props);
// Define your state object here
this.state = {
name: ‘Jane Doe’
}
}
render(){
return <h1>Hello { this.state.name }</h1>;
}
}
Notice that the constructor accepts props
as an argument, which are then passed to super()
. Adding super()
is a must when using the constructor.
Passing props
is not necessary unless you are making use of them in the component. From the Greeting
component above, it’s not necessary to pass props
to either the constructor
or super()
, that is to say, the component can be written like so:
class Greeting extends React.Component {
constructor() {
super();
// Define your state object here
}
// Define your render method here
}
However, the React docs recommend that you always pass props
in order to guarantee compatibility with potential future features
State is accessed using this.state
as seen in the Greeting
component’s h
1 tag.
State is initiated using
this.state
, however, all subsequent changes to state are made usingthis.setState
. Usingthis.setState
ensures that the components affected by the change in state are re-rendered in the browser.
Investigating State using React Developer tools
One way to accelerate your understanding of React is to make use of the React devtools created by the team at Facebook. The power of React devtools is most apparent when you need to debug your React app by doing a deep dive into the code. The tools enable you to investigate how React is working below the surface when the app is rendered in the browser.
Installing the React Developer tools
The devtools are available for download on both Mozilla Firefox Add-ons and the Chrome Web Store. Follow the appropriate link to install the devtools depending on which browser you have installed on your computer.
Throughout the rest of this book, Chrome will be used as the browser of choice. In order to confirm successful installation of the devtools on Chrome, open the developer tools window using Cmd+Opt+I
on a Mac or Ctrl+Alt+I
on a windows PC. You should now see a React tab.
Using the React Devtools
With the Greeting
component from earlier in this chapter rendered in your browser, open the developer tools and navigate to the React tab. You should see something similar to this
Mastery of the React DevTools will enable you to gain a better understanding of React’s inner workings and to quickly debug React applications.
Project Three
To better understand the basic use cases of state in React, we shall build a simple application that allows us to create and render records.
What we’ll build
A React app that enables us to keep track of our friends’ names
and ages
. The app provides a form that we shall use to enter their details. It then renders our friends’ details in beautiful Bootstrap 4 cards.
The finished application looks like this:
Getting started
Download or clone the projects’ starter files from the repository to your computer so that you can follow along.
In order to run the code examples in this chapter on your machine, you have to first install a server globally using NodeJS. Below is the command to install the http-server
on your machine. Open your terminal and run:-
npm install http-server -g
After the installation is done, cd
into the Chapter 3 folder then the starter-code folder. Within there run the command below to start the server:-
http-server .
In case you make changes to the code and they are not shown in the browser even after a refresh, try hard refreshing that tab or page.
Below is what will be shown in the browser when you open the localhost url displayed in your terminal.
Inside src/index.js
, there’s a simple class component that renders JSX for a form with name
and age
fields, and a save
button.
Adding state to the component
In order to display the names
and ages
added to the application, we need to add state to our Application
component. We’ll start by adding default state which contains a dummy name and age which will display whenever the page is rendered in the browser.
We do this by initiating state with this.state
inside the component’s constructor
method like so:
constructor(props) {
super(props);
this.state = {
data: [
{
name: ‘John’,
age: 20
}
]
}
}
If you are following along, copy and paste the snippet into the Application
component just before the render function.
Rendering data from state
To render the state data, a Card
presentation component is defined with the functionality to display the name
and age
from the props
passed to it as shown below.
const Card = props =>
<div className=”col-md-6 col-lg-3">
<div className=”card mb-3">
<div className=”card-body”>
<p className=”card-title”>
<span>Name: </span>{props.info.name}
</p>
<p className=”card-text”>
<span>Age: </span>{props.info.age}
</p>
</div>
</div>
</div>;
Add this Card
component to the index.js
file below the Application
component but before the ReactDOM
code.
To display the data in state, we need to access the data array using this.state.data
and then use JavaScript’s map
function to loop through the array so that each of its elements is rendered on the page.
<div className=”row”>
{
this.state.data.map(info => <Card info={info}/>)
}
</div>
The statement containing the Card
component is wrapped within a Bootstrap row so that it is displayed within the Bootstrap grid and placed just after the second <hr/>
within the class component’s render
function.
A card is then displayed in the browser as shown below.
Checking the console within the developer tools window reveals errors as shown in the screenshot below.
This means that we need to give each Card
element a key
so that React can identify each Card
and know what to do when changes occur to any one of them. This can easily be fixed using the map
function.
The map
function accepts a function that accepts two arguments, the array element (info
) and its index
; this means that we can use the index
as a key
to the Card
component.
Alter the code to match the code within the snippet below.
<div className=”row”>
{
this.state.data.map(
(info, index) => <Card key={index} info={info}/>
)
}
</div>
This should clear the error in the console.
Using
index
as akey
in amap
function typically works well for small applications whose data is not that dynamic. However, as applications and data sources get larger, using theindex
as akey
becomes unreliable. In these cases, it’s recommended to use a truly uniquekey
, for example anid
. In the project above, every object in state can be assigned anid
field and thisid
can then be used as thekey
like so;key={info.id}
.
Adding form data to state
The application is incomplete without the functionality to add new names
and ages
via the form. This requires knowledge of handling user input , a topic that is covered in the next chapter. We’ll stop here for now, and complete building the application in Chapter 4.
If you found this article the least bit helpful, hit the 👏 button and help me get it to more people who need help getting started with React. I’d appreciate your responses with your thoughts as well — whatever they might be. I’m on Twitter if you need to chat.