Understanding State In React — A Practical Approach

Challenge

Figure 1: The UI we’re building

React Intro

$ cd /home
$ cd /home/desktop
$ cd /htdocs
$ create React App my-app
Figure 2: Reacts initial file structure
Figure 3: our final file structure
$ rm app.test.js index.css logo.svg

Approaching The Solution

Design

Figure 4: the design we aspire for
$ touch styles.css
/* styles.css file */.column {
padding: 10px;
height: 250px;
}
.left {
float: left;
display: block;
width: 35%;
}
.right {
float: right;
display: block;
width: 65%;
}

Components

$ mkdir Components
$ touch SideBarInfo.js Thumbnail.js Sample.css

Thumbnail

/* 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;
}
Figure 5
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;

SideBarInfo

Figure 6: SideBarInfo view
/* 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

What Is State ?

class App extends React.Component { 
constructor(props) {
super(props);
this.state = { };
}
}
Figure 7: UI display of work array showing two Items in the right column
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
}
]
};
}
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>
);
}
}
// 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} />;
};
/* 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
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

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

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store