Understanding State In React — A Practical Approach

N G Onike
14 min readFeb 10, 2021

This article hinges on the application of UI in solving the challenge. To fully grasp this article, one should already be familiar with;

having set up React, HTML, CSS, JSX(JavaScript XML) and JavaScript (JS) ES6+ syntax.

However there is still guidance on basic setup herein.

The predisposed reader should have encountered:

  • Bash Terminal, Node Package Manager (NPM)

By the end of this article, the ardent reader should understand what state in React is about and even conjure a basic UI implementation using Props.

I go about this article by way of an example. I present a simple challenge I encountered learning React and how going about its solution improved my knowledge of state.

Challenge

Enable dynamic display of different information on the left column from varying card components on the right column of the same page on the click of the image card item.

See Figure 1 below

Figure 1: The UI we’re building

React Intro

React in this case is a technology. A type of software championed by facebook which serves the function of improving display UI(User Interface) and UX(User eXperience).

It is a library (not a framework) that facilitates easy storage, retrieval and reuse of UI components across a software project. React is known for its speed as it reduces webpage load time significantly through some software magic I’m not about to go into as that goes beyond our focus.

React is straight forward at this point and is quite popular in development circles.

Though our challenge is encapsulated within a Code Sandbox to abstract build irrelevancies, this tutorial will still carry those working in an IDE terminal along.

… and so, we begin our journey at the Terminal. We can navigate to the folder where we’d like to house our project or head home using the cd command(cmd):

$ cd /home

it could also be

$ cd /home/desktop

OR

$ cd /htdocs

depending on where we normally house our projects.

In our parent folder is where the engine begins by the push of the cmd

$ create React App my-app

this generates a general file structure for the folder my-app (this could be any name you wish) in our chosen IDE as shown below

Figure 2: Reacts initial file structure

the eventual/final file structure of this sample will turn out like this below

Figure 3: our final file structure

This tutorial would be conducted mainly in the /src folder.

Next, we clear out extra generated files irrelevant to this project and strip our scaffold to the bare minimum.

Just what we need. We take out:

  • app.test.js
  • index.css
  • logo.svg

The bash command to execute this is :

$ rm app.test.js index.css logo.svg

Approaching The Solution

In tackling React, we break down our entire code into components. This facilitates ease of understanding our code by segmenting the relationships between different design features. This little project uses 2 components housed in the files: SideBarInfo.js and Thumbnail.js

These are most of what we need and what we’d be working with.

The stylesheets needed are added to the various folders where their related files are housed: /src and /Components/...

We’d go further into the stylesheets later below.

Design

The idea is to be able to click on an Item from the COLUMN 2 on the right and have expanded details about it show up on COLUMN 1 on the left.

Keep the columns in mind as we’d refer to them throughout this piece.

See figure below

Figure 4: the design we aspire for

by the design above, we can break down the single page into two columns. This can be achieved by CSS in the stylesheet ( styles.css ) . Let’s house this in our /src folder

we can create the styles file via the terminal with the cmd

$ touch styles.css

We populate our styles.css file with the design parameters defining our column and classes for the left and the right. This stylesheet would later be invoked in our main page ../App.js via JavaScripts import function.

/* styles.css file */.column {
padding: 10px;
height: 250px;
}
.left {
float: left;
display: block;
width: 35%;
}
.right {
float: right;
display: block;
width: 65%;
}

Components

Now we have our page split in 2 different columns, we can proceed to break down what goes into each column.

The left column ( COLUMN 1 ) will house our first component which is the view for the SideBarInfo which shows details of a clicked item including its corresponding Image and name

from the right column ( COLUMN 2 ) which houses our second component which is the Thumbnail that shows an ItemImage and its Name.

Keep in mind that Item List will be stored in an array on our main display page ../App.js and in this same file is where understanding our Props come into play ( we’d get to this later ).

We navigate to our /src folder and create the folder for our components

$ mkdir Components

next we navigate to our /Components folder where we create the file components and their stylesheet with the cmd

$ touch SideBarInfo.js Thumbnail.js Sample.css

Thumbnail

We navigate to our ../Components folder where we focus on the thumbnail component starting with the folder css file ( Sample.css ) which we edit below. This css contains a barebones styling for our Item

Much ado about naming conventions, we name an Item css class;

furthermore, we’d be referring to Item and Work interchangeably since Work is how we’ll be describing each Item by syntax ( more on this later below )

Below, we delve into the component stylesheet that defines the parameters of what a single Item in COLUMN 2 should look like. See below.

/* Sample.css file */.Work .image-container {
height: 10rem;
margin-bottom: 1rem;
border-radius: 30px;
display: flex;
flex-wrap: wrap;
position: inherit;
width: 100%;
max-width: 100%;
flex-direction: column;
justify-content: center;
overflow: hidden;
background: #000;
}

Right now, we imagine a single Item to comprise of a thumbnail which houses/displays a single Item Image. Below this item we will display its corresponding Item name Information in a html <div> tag in our Thumbnail.js file.

See figure 5 below

Figure 5

Done with the stylesheet, we proceed to work on the Thumbnail.js file, where we

  • import react
  • import our stylesheet ( Sample.css )
  • define the Work/Item props
  • placing the Work/Item image in a div and defining its action after a click event
  • placing the Work/item name beneath the image
import React from "react"; //standard import React function
import "./Sample.css"; // we import the sample stylesheet
//below we create our thumbnail class for this thumbnail componentclass Thumbnail extends React.Component {
render() {
return (
<div>
<div className="column right">
<div className="Work"
onClick={(e) => this.props.click(this.props.work)} >
// ES6+ onClick handles the click event for an item image
<div className="image-container">//item image style class
<img
src={this.props.work.imageSrc}
alt={this.props.work.imageSrc}
/>
</div>
<div className="">
// display the items' name info below
<p> {this.props.work.work}</p>
</div>
</div>
</div>
</div>
);
}
}
// export this component making it available around the application
export default Thumbnail;

Having built the thumbnail component for COLUMN 2, we proceed to build the SidebarBarInfo for COLUMN 1.

SideBarInfo

We navigate back to our /Component folder where we face the SideBarInfo.js file which will house the layout for what our COLUMN 1 display will look like.

Figure 6: SideBarInfo view

Using the same stylesheet, we embark on defining the UI parameters for the SideBarInfo component below in JSX.

  • we import the React
  • we import the stylesheet
  • we define/display the image style and its prop
  • we display the Item name and further details
/* SideBarInfo.js file */import React from "react";  // standard import React function
import "./Sample.css"; // imports the Sample stylesheet
// below we use a function instead of a class(both can be interchangeable depending on usage)function SidebarInfo(props) {
return (
<div>
<div className="Work">
<h1> NAME </h1> // random header title
<div className="image-container">
// image styling above and Image props below
// see image dimensions below
<img
width="150"
height="150"
src={props.imageSrc}
alt={props.imageSrc}
/>
</div>
<p> {props.work} </p> // name of the item/work props
<p> {props.view} </p> // other details:view of the item/work
</div>
</div>
);
}
// lastly we export the entire component file for recall/reuse across our application as belowexport default SidebarInfo;

App.js

We navigate back to our /src folder where we turn our attention to the main page where our App component is a stateful class.

You’ve been reading about state from the start of this write up. It comes into play at this point where we tie our project together.

What Is State ?

State here is a capsule within a component which contains data that is managed within that component. State determines how a component behaves and is rendered (more on render below). Not all components have/use state and those that don’t are referred to as stateless components while those that do are stateful. There are many ways a component can access and manage States’ data such as the use of props, setState , useState and Hooks. An In-depth explanation is beyond the scope of this tutorial.

Let’s dive into how this comes in.

So, our COLUMN 2 holds a list of items and we’ve designed the container for a single item ( Thumbnail.js ). How then do we list the items and get them to show up in our page ?

We begin our App.js file by establishing a class component (App) with a Constructor method that accepts props, and at the moment, is a container housing an empty object.

This empty object would be filled with our array/list of Items and their details subsequently below.

class App extends React.Component { 
constructor(props) {
super(props);
this.state = { };
}
}

The array of Items are to be referred to as : works while a single item in the array is titled :work.

works is essentially a dummy list of our items.

works is an array of our Items comprising of :

  • an image link known as — imageSrc
  • one detail known as — view ( view can hold a link or any string detail )
  • a boolean (true or false) value known as — selected ( this variable will come into play further below ).

*Note* that you feel free to add more details to your Items(Work) array, but here we use only 2 Items as shown below.

Figure 7: UI display of work array showing two Items in the right column

See what I mean in the code below( The image links used are sourced from Creative Commons)

class App extends React.Component {
constructor(props) {
super(props);
this.state = {
works: [
{
id: 0,
work: "Work 1",
imageSrc:
"https://images.unsplash.com/photo-1584608168573-b6eec7a04fd7?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=701&q=80",
view: "#",
selected: false
},
{
id: 1,
work: "Work 2",
imageSrc:
"https://images.unsplash.com/photo-1581665269479-57504728e479?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=701&q=80",
view: "#",
selected: false
}
]
};
}

Now that we have our array captured in State, we can think about how to get these Items showing.

Time to bring in render() I’d briefly recall a couple of things that render() is and i’d leave out what it’s not.

  • The render function performs the role of displaying specified code in an html element such as a <div> .
  • It enables interaction between various components in a react application.
  • Using a prop, render can divulge full or parts of its state and components’ logic to other components.
  • A render is triggered once there’s any change in the components state (part of the magic that makes react fast and responsive)
  • A render can be accessed by the DOM (view layer) and can relay display

In our render() function for our App component, we’d display the column layout and the Items in our state.

We add the code to a render function below.

Let’s dive

class App extends React.Component {
constructor(props) {
super(props);
this.state = {
works: [
{
id: 0,
work: "Work 1",
imageSrc:
"https://images.unsplash.com/photo-1584608168573-b6eec7a04fd7?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=701&q=80",
view: "#",
selected: false
},
{
id: 1,
work: "Work 2",
imageSrc:
"https://images.unsplash.com/photo-1581665269479-57504728e479?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=701&q=80",
view: "#",
selected: false
}
]
};
}// see the added Render function here below render() {
return (
<div className="column ">
<span>
//*NOTE* Reacts class components and JSX allows you to call in //functions from the same component
//SideBarInfo's column (left) right below
<div className="left">
{ } //empty placeholder for JSX
</div>
// Thumbnail's column for Items/works array below

<div className="right">
{ } //empty placeholder for JSX
</div>
</span>
</div>
);
}
}

Our App component is beginning to fill out. We have our array of Items stored in state, we have our column parameters called in a render() function. But we can’t see much and have a bug or two.

So, how do we link it all up and display i.e. our stateful App component ( that houses an array of Items in state and also renders an empty column arrangement ) + our SidebarInfo functional component (which accepts a prop and returns its data) + a single lonely Thumbnail class component ( which renders an empty shell that will contain an Items data ?

App + SidebarInfo + Thumbnail = View

* Tip* Class components in React accept props naturally so props doesn’t need to be declared but can be called with this.props. Functional components on the other hand have to declare props as in fn_name(props){props.ObjectName} ( see usage in SideBarInfo.js)

Our COLUMN 2 will house our Items list which would be Thumbnails of the Items currently in our App components state.

Our COLUMN 1 will house a SideBarInfo which can display a clicked Thumbnail and all its data in our state if need be.

We will use 3 functions to go about the logic of linking up our components. All these functions will be in our App component which houses our state. We will call our stylesheet and the other components in our ../App.js file through JavaScripts import function as well.

The functions we will use are :

  • makeWorks() : this function iterates through the works array and returns each Items data in a thumbnail which listens for a click event
  • handleCardClick() : this function accepts an id and Thumbnail ( react allows you to call a global component in a function provided it has been imported ). It listens for a click event and registers the id of the clicked item while changing its selected value based on the event and the storing it in state.
  • showWorks() : this functions accepts works , iterates through each one, picks the selected array and displays its data in as a SideBarInfo via props.
// JavaScripts ES6 map method iterates the array of works and returns an item thumbnailmakeWorks = (works) => {   
return works.map((work) => {
return (
<Thumbnail
work={work}
click={(e) => this.handleCardClick(work.id, e)}
key={work.id}
/>
);
});
};
// this function below accepts an id and Thumbnail componenthandleCardClick = (id, Thumbnail) => {
console.log(id);
// we define works variable below

let works = [...this.state.works];
// our ternary operator below stores the boolean value in the //variableworks[id].selected = works[id].selected ? false : true;

// this ES6 method ensures that unselected values are false
works.forEach((work) => {
if (work.id !== id) {
work.selected = false;
}
});
// below we mutate our state by changing the value of selected this.setState({
works
});
};
// vanilla JavaScript loops through the works array and uses props // to display selected item/work in SideBarInfo showWorks = (works) => {
let i = 0;
var w = [];
while (i < works.length) {
if (works[i].selected) {
w = works[i];
}
i++;
}
return <SidebarInfo imageSrc={w.imageSrc} work={w.work} />;
};

*Note* Recall that SideBarInfo is a functional component that accepts props. Hence we can call our data from an item in state and use it to populate SideBarInfos shell in one function. We can then return that that function in our render() ( behold JavaScript Inception! ).

Likewise, Thumbnail already defines the work object it accepts via props so when we call it in our App component, we assign it data from our state and allow the component display it. Props are immutable and read-only and cannot be modified or changed like state.

Also, recall the Constructor method ? which accepts props ? Well, our 3 functions shown above are going to go into our App Class and we will bind them to that Constructor method to make state available to our functions.

below we bind these functions together in state,

call in our component and style imports,

rework our render() to facilitate our display

and call it a day.

Let’s dive

/* App.js file */// we import components and styling belowimport React from "react";
import Thumbnail from "./Components/Thumbnail";
import SidebarInfo from "./Components/SideBarInfo";
import "./styles.css";
// below we add export method to our App Component export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
works: [
{
id: 0,
work: "Work 1",
imageSrc:
"https://images.unsplash.com/photo-1584608168573-b6eec7a04fd7?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=701&q=80",
view: "#",
selected: false
},
{
id: 1,
work: "Work 2",
imageSrc:
"https://images.unsplash.com/photo-1581665269479-57504728e479?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=701&q=80",
view: "#",
selected: false
}
]
};
// we bind the functions to our constructor method like this below this.makeWorks = this.makeWorks.bind(this);
this.handleCardClick = this.handleCardClick.bind(this);
this.showWorks = this.showWorks.bind(this);
}
// here comes our functions in shining armor below makeWorks = (works) => {
return works.map((work) => {
return (
<Thumbnail
work={work}
click={(e) => this.handleCardClick(work.id, e)}
key={work.id}
/>
);
});
};
handleCardClick = (id, Thumbnail) => {
console.log(id);
let works = [...this.state.works]; works[id].selected = works[id].selected ? false : true; works.forEach((work) => {
if (work.id !== id) {
work.selected = false;
}
});
this.setState({
works
});
};
showWorks = (works) => {
let i = 0;
var w = [];
while (i < works.length) {
if (works[i].selected) {
w = works[i];
}
i++;
}
return <SidebarInfo imageSrc={w.imageSrc} work={w.work} />;
};
render() {
return (
<div className="column ">
<span>
// The JSX below renders our showWorks()-it gives it access to state // below. This displays SideBarInfo for the left: COLUMN 1

<div className="left">
{this.showWorks(this.state.works)}
</div>
// The JSX below renders our makeWorks()-it gives it access to state //here. It displays item Thumbnails for the right COLUMN 2 <div className="right">
{this.makeWorks(this.state.works)}
</div>

</span>
</div>
);
}
}
// export default App;
// using the export above is an alternative to adding it to the //class above

We can now save our files. Your /index.js file should call your App component and should look as below

import React from "react";
import ReactDOM from "react-dom";
import App from "./App";const rootElement = document.getElementById("root");
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
rootElement
);

Recap

This piece tackles a UI display challenge. It goes about this via props, state and onClick in React. Our final view would show a UI display akin to Figure 1

Lastly, this tutorial only displays 2 Items. Feel free to add more Items to your array and play around with the CSS to accommodate your own styling.

You can view a working version of this tutorial in this SandBox

This article is stored on my blog https://sojourn.ngonike.dev

--

--

N G Onike

Communications Specialist: Journalism, Digital Marketing and Web Software Development.