React Unit 2 & 3
React Unit 2 & 3
React JS
What is React?
React, sometimes referred to as a frontend is a JavaScript library created by
Facebook.
React finds out what changes have been made, and changes only what
needs to be changed.
You will learn the various aspects of how React does this in the rest of this
tutorial.
React.JS History
Current version of React.JS is V18.0.0 (April 2022).
To use React in production, you need npm which is included with Node.js.
To get an overview of what React is, you can write React code directly in
HTML.
Start by including three scripts, the first two let us write React code in our
JavaScripts, and the third, Babel, allows us to write JSX syntax and ES6 in
older browsers.
You will learn more about JSX in the React JSX chapter.
Example
Include three CDN's in your HTML file:
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/react@18/umd/react.development.js"
crossorigin></script>
<script src="https://unpkg.com/react-dom@18/umd/react-
dom.development.js" crossorigin></script>
<script
src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
</head>
<body>
<div id="mydiv"></div>
<script type="text/babel">
function Hello() {
return <h1>Hello World!</h1>;
}
ReactDOM.render(<Hello />, document.getElementById('mydiv'))
</script>
</body>
</html>
This way of using React can be OK for testing purposes, but for production
you will need to set up a React environment.
cd my-react-app
npm start
A new browser window will pop up with your newly created React App! If not,
open your browser and type localhost:3000 in the address bar.
The result:
Look in the my-react-app directory, and you will find a src folder. Inside
the src folder there is a file called App.js, open it and it will look like this:
/myReactApp/src/App.js:
function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
Notice that the changes are visible immediately after you save the file, you
do not have to reload the browser!
Example
Replace all the content inside the <div className="App"> with a <h1> element.
function App() {
return (
<div className="App">
<h1>Hello World!</h1>
</div>
);
}
Notice that we have removed the imports we do not need (logo.svg and
App.css).
The result:
What's Next?
Now you have a React Environment on your computer, and you are ready to
learn more about React.
In the rest of this tutorial we will use our "Show React" tool to explain the
various aspects of React, and how they are displayed in the browser.
If you want to follow the same steps on your computer, start by stripping
down the src folder to only contain one file: index.js. You should also remove
any unnecessary lines of code inside the index.js file to make them look like
the example in the "Show React" tool below:
Example
index.js:
import React from 'react';
import ReactDOM from 'react-dom/client';
root.render(myFirstElement);
React ES6
What is ES6?
ES6 stands for ECMAScript 6.
ECMAScript was created to standardize JavaScript, and ES6 is the 6th version
of ECMAScript, it was published in 2015, and is also known as ECMAScript
2015.
Variables
Before ES6 there was only one way of defining your variables: with
the var keyword. If you did not define them, they would be assigned to the
global object. Unless you were in strict mode, then you would get an error if
your variables were undefined.
Now, with ES6, there are three ways of defining your variables: var, let,
and const.
Var
var x = 5.6;
If you use var inside of a block, i.e. a for loop, the variable is still available
outside of that block.
let
let x = 5.6;
let is the block scoped version of var, and is limited to the block (or
expression) where it is defined.
If you use let inside of a block, i.e. a for loop, the variable is only available
inside of that loop.
const
const x = 5.6;
const is a variable that once it has been created, its value can never change.
Classes
ES6 introduced classes.
Example
A simple class constructor:
class Car {
constructor(name) {
this.brand = name;
}
}
Notice the case of the class name. We have begun the name, "Car", with an
uppercase character. This is a standard naming convention for classes.
Example
Create an object called "mycar" based on the Car class:
class Car {
constructor(name) {
this.brand = name;
}
}
Method in Classes
You can add your own methods in a class:
Example
Create a method named "present":
class Car {
constructor(name) {
this.brand = name;
}
present() {
return 'I have a ' + this.brand;
}
}
const mycar = new Car("Ford");
mycar.present();
As you can see in the example above, you call the method by referring to the
object's method name followed by parentheses (parameters would go inside
the parentheses).
Class Inheritance
To create a class inheritance, use the extends keyword.
A class created with a class inheritance inherits all the methods from another
class:
Example
Create a class named "Model" which will inherit the methods from the "Car"
class:
class Car {
constructor(name) {
this.brand = name;
}
present() {
return 'I have a ' + this.brand;
}
}
class Model extends Car {
constructor(name, mod) {
super(name);
this.model = mod;
}
show() {
return this.present() + ', it is a ' + this.model
}
}
const mycar = new Model("Ford", "Mustang");
mycar.show();
By calling the super() method in the constructor method, we call the parent's
constructor method and gets access to the parent's properties and methods.
Arrow Functions
Arrow functions allow us to write shorter function syntax:
Before:
hello = function() {
return "Hello World!";
}
It gets shorter! If the function has only one statement, and the statement
returns a value, you can remove the brackets and the return keyword:
Note: This works only if the function has only one statement.
In fact, if you have only one parameter, you can skip the parentheses as
well:
Array Methods
There are many JavaScript array methods.
The .map() method allows you to run a function on each item in the array,
returning a new array as the result.
Example
Generate a list of items from an array:
Destructuring
To illustrate destructuring, we'll make a sandwich. Do you take everything
out of the refrigerator to make your sandwich? No, you only take out the
items you would like to use on your sandwich.
Destructing Arrays
Shri Shambhubhai V. Patel College of Computer Science & Business Management
SUB:501_AWD Unit 2 & 3
Before:
const vehicles = ['mustang', 'f-150', 'expedition'];
// old way
const car = vehicles[0];
const truck = vehicles[1];
const suv = vehicles[2];
With destructuring:
const vehicles = ['mustang', 'f-150', 'expedition'];
If we only want the car and suv we can simply leave out the truck but keep
the comma:
Example
function calculate(a, b) {
const add = a + b;
const subtract = a - b;
const multiply = a * b;
const divide = a / b;
Destructuring Objects
Here is the old way of using an object inside a function:
Before:
const vehicleOne = {
brand: 'Ford',
model: 'Mustang',
type: 'car',
year: 2021,
color: 'red'
}
myVehicle(vehicleOne);
// old way
function myVehicle(vehicle) {
const message = 'My ' + vehicle.type + ' is a ' + vehicle.color + ' '
+ vehicle.brand + ' ' + vehicle.model + '.';
}
With destructuring:
const vehicleOne = {
brand: 'Ford',
model: 'Mustang',
type: 'car',
year: 2021,
color: 'red'
}
myVehicle(vehicleOne);
Example
const vehicleOne = {
brand: 'Ford',
model: 'Mustang',
type: 'car',
year: 2021,
color: 'red',
registration: {
city: 'Houston',
state: 'Texas',
country: 'USA'
}
}
myVehicle(vehicleOne)
Spread Operator
The JavaScript spread operator (...) allows us to quickly copy all or part of
an existing array or object into another array or object.
Example
const numbersOne = [1, 2, 3];
const numbersTwo = [4, 5, 6];
const numbersCombined = [...numbersOne, ...numbersTwo];
Example
Assign the first and second items from numbers to variables and put the rest in
an array:
Example
Combine these two objects:
const myVehicle = {
brand: 'Ford',
model: 'Mustang',
color: 'red'
}
const updateMyVehicle = {
type: 'car',
year: 2021,
color: 'yellow'
}
Notice the properties that did not match were combined, but the property
that did match, color, was overwritten by the last object that was
passed, updateMyVehicle. The resulting color is now yellow.
Modules
JavaScript modules allow you to break up your code into separate files.
Export
You can export a function or variable from any file.
Let us create a file named person.js, and fill it with the things we want to
export.
Named Exports
You can create named exports two ways. In-line individually, or all at once at
the bottom.
In-line individually:
person.js
Default Exports
Let us create another file, named message.js, and use it for demonstrating
default export.
Example
message.js
Import
You can import modules into a file in two ways, based on if they are named
exports or default exports.
Ternary Operator
The ternary operator is a simplified conditional operator like if / else.
Before:
if (authenticated) {
renderApp();
} else {
renderLogin();
With Ternary
authenticated ? renderApp() : renderLogin();
The purpose of the function is to display the specified HTML code inside the
specified HTML element.
There is another folder in the root directory of your React project, named
"public". In this folder, there is an index.html file.
You'll notice a single <div> in the body of this file. This is where our React
application will be rendered.
Example
Display a paragraph inside an element with the id of "root":
ReactDOM.render(<p>Hello</p>, document.getElementById('root'));
<body>
<div id="root"></div>
</body>
Note that the element id does not have to be called "root", but this is the
standard convention.
Do not worry if the syntax is unfamiliar, you will learn more about JSX in the
next chapter.
Example
Create a variable that contains HTML code and display it in the "root" node:
const myelement = (
<table>
<tr>
<th>Name</th>
</tr>
<tr>
<td>John</td>
</tr>
<tr>
<td>Elsa</td>
</tr>
</table>
);
ReactDOM.render(myelement, document.getElementById('root'));
It does NOT have to be a <div> element and it does NOT have to have
the id='root':
Example
The root node can be called whatever you like:
<body>
<header id="sandy"></header>
</body>
ReactDOM.render(<p>Hallo</p>, document.getElementById('sandy'));
React JSX
What is JSX?
JSX stands for JavaScript XML.
Coding JSX
JSX allows us to write HTML elements in JavaScript and place them in the
DOM without any createElement() and/or appendChild() methods.
You are not required to use JSX, but JSX makes it easier to write React
applications.
Here are two examples. The first uses JSX and the second does not:
Example 1
JSX:
Example 2
Without JSX:
As you can see in the first example, JSX allows us to write HTML directly
within the JavaScript code.
Expressions in JSX
With JSX you can write expressions inside curly braces { }.
Example
Execute the expression 5 + 5:
Example
Create a list with three list items:
const myElement = (
<ul>
<li>Apples</li>
<li>Bananas</li>
<li>Cherries</li>
</ul>
);
So if you like to write two paragraphs, you must put them inside a parent
element, like a div element.
Example
Wrap two paragraphs inside one DIV element:
const myElement = (
<div>
<p>I am a paragraph.</p>
<p>I am a paragraph too.</p>
</div>
);
JSX will throw an error if the HTML is not correct, or if the HTML misses a
parent element.
Alternatively, you can use a "fragment" to wrap multiple lines. This will
prevent unnecessarily adding extra nodes to the DOM.
Example
Wrap two paragraphs inside a fragment:
const myElement = (
<>
<p>I am a paragraph.</p>
<p>I am a paragraph too.</p>
</>
);
Example
Close empty elements with />
Example
Use attribute className instead of class in JSX:
Conditions - if statements
React supports if statements, but not inside JSX.
Option 1:
Example
Write "Hello" if x is less than 10, otherwise "Goodbye":
const x = 5;
let text = "Goodbye";
if (x < 10) {
text = "Hello";
}
const myElement = <h1>{text}</h1>;
Option 2:
Example
Write "Hello" if x is less than 10, otherwise "Goodbye":
const x = 5;
const myElement = <h1>{(x) < 10 ? "Hello" : "Goodbye"}</h1>;
React Components
Components are like functions that return HTML elements.
React Components
Components are independent and reusable bits of code. They serve the same
purpose as JavaScript functions, but work in isolation and return HTML.
In older React code bases, you may find Class components primarily used. It
is now suggested to use Function components along with Hooks, which were
Class Component
A class component must include the extends React.Component statement. This
statement creates an inheritance to React.Component, and gives your
component access to React.Component's functions.
The component also requires a render() method, this method returns HTML.
Example
Create a Class component called Car
A Function component also returns HTML, and behaves much the same way
as a Class component, but Function components can be written using much
less code, are easier to understand, and will be preferred in this tutorial.
Example
Create a Function component called Car
function Car() {
return <h2>Hi, I am a Car!</h2>;
}
Rendering a Component
Now your React application has a component called Car, which returns
an <h2> element.
Example
Display the Car component in the "root" element:
Props
Components can be passed as props, which stands for properties.
Props are like function arguments, and you send them into the component as
attributes.
Example
Use an attribute to pass a color to the Car component, and use it in the
render() function:
function Car(props) {
return <h2>I am a {props.color} Car!</h2>;
}
Components in Components
We can refer to components inside other components:
Example
Use the Car component inside the Garage component:
function Car() {
return <h2>I am a Car!</h2>;
}
function Garage() {
return (
<>
<h1>Who lives in my Garage?</h1>
<Car />
</>
);
}
Components in Files
React is all about re-using code, and it is recommended to split your
components into separate files.
To do that, create a new file with a .js file extension and put the code inside
it:
Example
This is the new file, we named it "Car.js":
function Car() {
return <h2>Hi, I am a Car!</h2>;
}
To be able to use the Car component, you have to import the file in your
application.
Example
Now we import the "Car.js" file in the application, and we can use
the Car component as if it was created here.
With the addition of Hooks, Function components are now almost equivalent
to Class components. The differences are so minor that you will probably
never need to use a Class component in React.
Even though Function components are preferred, there are no current plans
on removing Class components from React.
This section will give you an overview of how to use Class components in
React.
Feel free to skip this section, and use Function Components instead.
React Components
Components are independent and reusable bits of code. They serve the same
purpose as JavaScript functions, but work in isolation and return HTML via a
render() function.
The component also requires a render() method, this method returns HTML.
Example
Create a Class component called Car
Now your React application has a component called Car, which returns
a <h2> element.
Example
Display the Car component in the "root" element:
root.render(<Car />);
Component Constructor
If there is a constructor() function in your component, this function will be
called when the component gets initiated.
The constructor function is also where you honor the inheritance of the
parent component by including the super() statement, which executes the
parent component's constructor function, and your component has access to
all the functions of the parent component (React.Component).
Example
Create a constructor function in the Car component, and add a color
property:
Example
class Car extends React.Component {
constructor() {
super();
render() {
Props
Another way of handling component properties is by using props.
Props are like function arguments, and you send them into the component as
attributes.
Example
Use an attribute to pass a color to the Car component, and use it in the
render() function:
render() {
root.render(<Car color="red"/>);
Example
class Car extends React.Component {
constructor(props) {
super(props);
render() {
root.render(<Car model="Mustang"/>);
Components in Components
We can refer to components inside other components:
Example
Use the Car component inside the Garage component:
render() {
render() {
return (
<div>
<Car />
</div>
);
root.render(<Garage />);
Components in Files
React is all about re-using code, and it can be smart to insert some of your
components in separate files.
To do that, create a new file with a .js file extension and put the code inside
it:
Note that the file must start by importing React (as before), and it has to end
with the statement export default Car;.
Example
This is the new file, we named it Car.js:
To be able to use the Car component, you have to import the file in your
application.
Example
Now we import the Car.js file in the application, and we can use
the Car component as if it was created here.
You might have noticed that we used state earlier in the component
constructor section.
The state object is where you store property values that belongs to the
component.
Example
Specify the state object in the constructor method:
constructor(props) {
super(props);
render() {
return (
<div>
<h1>My Car</h1>
</div>
);
Example
Specify all the properties your component need:
constructor(props) {
super(props);
this.state = {
brand: "Ford",
model: "Mustang",
color: "red",
year: 1964
};
render() {
return (
<div>
<h1>My Car</h1>
</div>
);
Example:
Refer to the state object in the render() method:
constructor(props) {
super(props);
this.state = {
brand: "Ford",
model: "Mustang",
color: "red",
year: 1964
};
render() {
return (
<div>
<h1>My {this.state.brand}</h1>
<p>
It is a {this.state.color}
{this.state.model}
from {this.state.year}.
</p>
</div>
);
When a value in the state object changes, the component will re-render,
meaning that the output will change according to the new value(s).
Example:
Add a button with an onClick event that will change the color property:
constructor(props) {
super(props);
this.state = {
brand: "Ford",
model: "Mustang",
color: "red",
year: 1964
};
changeColor = () => {
this.setState({color: "blue"});
render() {
return (
<div>
<h1>My {this.state.brand}</h1>
<p>
It is a {this.state.color}
{this.state.model}
from {this.state.year}.
</p>
<button
type="button"
onClick={this.changeColor}
>Change color</button>
</div>
);
Always use the setState() method to change the state object, it will ensure
that the component knows its been updated and calls the render() method
(and all the other lifecycle methods).
Lifecycle of Components
Each component in React has a lifecycle which you can monitor and
manipulate during its three main phases.
Mounting
Mounting means putting elements into the DOM.
React has four built-in methods that gets called, in this order, when
mounting a component:
1. constructor()
2. getDerivedStateFromProps()
3. render()
4. componentDidMount()
The render() method is required and will always be called, the others are
optional and will be called if you define them.
constructor
The constructor() method is called before anything else, when the component
is initiated, and it is the natural place to set up the initial state and other
initial values.
The constructor() method is called with the props, as arguments, and you
should always start by calling the super(props) before anything else, this will
initiate the parent's constructor method and allows the component to inherit
methods from its parent (React.Component).
Example:
The constructor method is called, by React, every time you make a
component:
constructor(props) {
super(props);
render() {
return (
);
root.render(<Header />);
getDerivedStateFromProps
The getDerivedStateFromProps() method is called right before rendering the
element(s) in the DOM.
This is the natural place to set the state object based on the initial props.
The example below starts with the favorite color being "red", but
the getDerivedStateFromProps() method updates the favorite color based on
the favcol attribute:
Example:
The getDerivedStateFromProps method is called right before the render method:
constructor(props) {
super(props);
render() {
return (
);
root.render(<Header favcol="yellow"/>);
render
The render() method is required, and is the method that actually outputs the
HTML to the DOM.
Example:
A simple component with a simple render() method:
render() {
return (
);
root.render(<Header />);
componentDidMount
The componentDidMount() method is called after the component is rendered.
This is where you run statements that requires that the component is already
placed in the DOM.
Example:
At first my favorite color is red, but give me a second, and it is yellow
instead:
constructor(props) {
super(props);
componentDidMount() {
setTimeout(() => {
this.setState({favoritecolor: "yellow"})
}, 1000)
render() {
return (
);
root.render(<Header />);
Updating
The next phase in the lifecycle is when a component is updated.
React has five built-in methods that gets called, in this order, when a
component is updated:
1. getDerivedStateFromProps()
2. shouldComponentUpdate()
3. render()
4. getSnapshotBeforeUpdate()
5. componentDidUpdate()
The render() method is required and will always be called, the others are
optional and will be called if you define them.
getDerivedStateFromProps
Also at updates the getDerivedStateFromProps method is called. This is the first
method that is called when a component gets updated.
This is still the natural place to set the state object based on the initial props.
The example below has a button that changes the favorite color to blue, but
since the getDerivedStateFromProps() method is called, which updates the state
with the color from the favcol attribute, the favorite color is still rendered as
yellow:
Example:
If the component gets updated, the getDerivedStateFromProps() method is
called:
constructor(props) {
super(props);
changeColor = () => {
this.setState({favoritecolor: "blue"});
render() {
return (
<div>
</div>
);
shouldComponentUpdate
In the shouldComponentUpdate() method you can return a Boolean value that
specifies whether React should continue with the rendering or not.
Example:
Stop the component from rendering at any update:
constructor(props) {
super(props);
shouldComponentUpdate() {
return false;
changeColor = () => {
this.setState({favoritecolor: "blue"});
render() {
return (
<div>
</div>
);
root.render(<Header />);
Example:
Same example as above, but this time the shouldComponentUpdate() method
returns true instead:
constructor(props) {
super(props);
shouldComponentUpdate() {
return true;
changeColor = () => {
this.setState({favoritecolor: "blue"});
render() {
return (
<div>
</div>
);
root.render(<Header />);
render
The render() method is of course called when a component gets updated, it
has to re-render the HTML to the DOM, with the new changes.
The example below has a button that changes the favorite color to blue:
Example:
Click the button to make a change in the component's state:
Shri Shambhubhai V. Patel College of Computer Science & Business Management
SUB:501_AWD Unit 2 & 3
constructor(props) {
super(props);
changeColor = () => {
this.setState({favoritecolor: "blue"});
render() {
return (
<div>
</div>
);
root.render(<Header />);
getSnapshotBeforeUpdate
In the getSnapshotBeforeUpdate() method you have access to
the props and state before the update, meaning that even after the update,
you can check what the values were before the update.
The example below might seem complicated, but all it does is this:
When the component is mounting it is rendered with the favorite color "red".
When the component has been mounted, a timer changes the state, and
after one second, the favorite color becomes "yellow".
This action triggers the update phase, and since this component has
a getSnapshotBeforeUpdate() method, this method is executed, and writes a
message to the empty DIV1 element.
Example:
Use the getSnapshotBeforeUpdate() method to find out what the state object
looked like before the update:
constructor(props) {
super(props);
componentDidMount() {
setTimeout(() => {
this.setState({favoritecolor: "yellow"})
}, 1000)
getSnapshotBeforeUpdate(prevProps, prevState) {
document.getElementById("div1").innerHTML =
componentDidUpdate() {
document.getElementById("div2").innerHTML =
render() {
return (
<div>
<div id="div1"></div>
<div id="div2"></div>
</div>
);
root.render(<Header />);
componentDidUpdate
The componentDidUpdate method is called after the component is updated in the
DOM.
The example below might seem complicated, but all it does is this:
When the component is mounting it is rendered with the favorite color "red".
When the component has been mounted, a timer changes the state, and the
color becomes "yellow".
This action triggers the update phase, and since this component has
a componentDidUpdate method, this method is executed and writes a message in
the empty DIV element:
Example:
The componentDidUpdate method is called after the update has been rendered in
the DOM:
constructor(props) {
super(props);
componentDidMount() {
setTimeout(() => {
this.setState({favoritecolor: "yellow"})
}, 1000)
componentDidUpdate() {
document.getElementById("mydiv").innerHTML =
render() {
return (
<div>
<div id="mydiv"></div>
</div>
);
root.render(<Header />);
Unmounting
The next phase in the lifecycle is when a component is removed from the
DOM, or unmounting as React likes to call it.
React has only one built-in method that gets called when a component is
unmounted:
• componentWillUnmount()
componentWillUnmount
The componentWillUnmount method is called when the component is about to be
removed from the DOM.
Example:
Click the button to delete the header:
constructor(props) {
super(props);
delHeader = () => {
this.setState({show: false});
render() {
let myheader;
if (this.state.show) {
};
return (
<div>
{myheader}
</div>
);
componentWillUnmount() {
render() {
return (
<h1>Hello World!</h1>
);
root.render(<Container />);
React Props
Props are arguments passed into React components.
React Props
React Props are like function arguments in JavaScript and attributes in HTML.
To send props into a component, use the same syntax as HTML attributes:
Example
Add a "brand" attribute to the Car element:
Example
Use the brand attribute in the component:
function Car(props) {
return <h2>I am a { props.brand }!</h2>;
}
Pass Data
Props are also how you pass data from one component to another, as
parameters.
Example
Send the "brand" property from the Garage component to the Car
component:
function Car(props) {
return <h2>I am a { props.brand }!</h2>;
}
function Garage() {
return (
<>
<h1>Who lives in my garage?</h1>
<Car brand="Ford" />
</>
);
}
If you have a variable to send, and not a string as in the example above, you
just put the variable name inside curly brackets:
Example
Create a variable named carName and send it to the Car component:
function Car(props) {
return <h2>I am a { props.brand }!</h2>;
}
function Garage() {
const carName = "Ford";
return (
<>
<h1>Who lives in my garage?</h1>
<Car brand={ carName } />
</>
);
}
Or if it was an object:
Example
Create an object named carInfo and send it to the Car component:
function Car(props) {
return <h2>I am a { props.brand.model }!</h2>;
}
function Garage() {
const carInfo = { name: "Ford", model: "Mustang" };
return (
<>
<h1>Who lives in my garage?</h1>
<Car brand={ carInfo } />
</>
);
}
Note: React Props are read-only! You will get an error if you try to change
their value.
React Events
Just like HTML DOM events, React can perform actions based on user
events.
React has the same events as HTML: click, change, mouseover etc.
Adding Events
React events are written in camelCase syntax:
React:
<button onClick={shoot}>Take the Shot!</button>
HTML:
<button onclick="shoot()">Take the Shot!</button>
Example:
Put the shoot function inside the Football component:
function Football() {
const shoot = () => {
alert("Great Shot!");
}
return (
<button onClick={shoot}>Take the shot!</button>
);
}
Passing Arguments
To pass an argument to an event handler, use an arrow function.
Example:
Send "Goal!" as a parameter to the shoot function, using arrow function:
function Football() {
const shoot = (a) => {
alert(a);
}
return (
<button onClick={() => shoot("Goal!")}>Take the shot!</button>
);
}
Example:
Arrow Function: Sending the event object manually:
function Football() {
const shoot = (a, b) => {
alert(b.type);
/*
'b' represents the React event that triggered the function,
in this case the 'click' event
*/
}
return (
<button onClick={(event) => shoot("Goal!", event)}>Take the
shot!</button>
);
}
if Statement
We can use the if JavaScript operator to decide which component to render.
Example:
We'll use these two components:
function MissedGoal() {
return <h1>MISSED!</h1>;
function MadeGoal() {
return <h1>Goal!</h1>;
Example:
Now, we'll create another component that chooses which component to
render based on a condition:
function Goal(props) {
if (isGoal) {
return <MadeGoal/>;
return <MissedGoal/>;
Example:
const root = ReactDOM.createRoot(document.getElementById('root'));
Example:
We can embed JavaScript expressions in JSX by using curly braces:
function Garage(props) {
return (
<>
<h1>Garage</h1>
<h2>
</h2>
</>
);
Example:
const cars = [];
Ternary Operator
Another way to conditionally render elements is by using a ternary operator.
Example:
Return the MadeGoal component if isGoal is true, otherwise return
the MissedGoal component:
function Goal(props) {
const isGoal = props.isGoal;
return (
<>
{ isGoal ? <MadeGoal/> : <MissedGoal/> }
</>
);
}
React Lists
In React, you will render lists with some type of loop.
If you need a refresher on the map() method, check out the ES6 section.
Example:
Let's render all of the cars from our garage:
function Car(props) {
return <li>I am a { props.brand }</li>;
}
function Garage() {
const cars = ['Ford', 'BMW', 'Audi'];
return (
<>
<h1>Who lives in my garage?</h1>
<ul>
{cars.map((car) => <Car brand={car} />)}
</ul>
</>
);
}
Keys
Keys allow React to keep track of elements. This way, if an item is updated
or removed, only that item will be re-rendered instead of the entire list.
Keys need to be unique to each sibling. But they can be duplicated globally.
Example:
Let's refactor our previous example to include keys:
function Car(props) {
function Garage() {
const cars = [
];
return (
<>
<ul>
</ul>
</>
);
root.render(<Garage />);
React Forms
Just like in HTML, React uses forms to allow users to interact with the web
page.
Example:
Add a form that allows users to enter their name:
function MyForm() {
return (
<form>
<label>Enter your name:
<input type="text" />
</label>
</form>
)
}
This will work as normal, the form will submit and the page will refresh.
We want to prevent this default behavior and let React control the form.
Handling Forms
Handling forms is about how you handle the data when it changes value or
gets submitted.
When the data is handled by the components, all the data is stored in the
component state.
You can control changes by adding event handlers in the onChange attribute.
We can use the useState Hook to keep track of each inputs value and
provide a "single source of truth" for the entire application.
Example:
Use the useState Hook to manage the input:
function MyForm() {
const [name, setName] = useState("");
return (
<form>
<label>Enter your name:
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
/>
</label>
</form>
)
}
Submitting Forms
You can control the submit action by adding an event handler in
the onSubmit attribute for the <form>:
Example:
Add a submit button and an event handler in the onSubmit attribute:
function MyForm() {
const [name, setName] = useState("");
return (
<form onSubmit={handleSubmit}>
<label>Enter your name:
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
/>
</label>
<input type="submit" />
</form>
)
}
To update the state, use square brackets [bracket notation] around the
property name.
Example:
Write a form with two input fields:
function MyForm() {
const [inputs, setInputs] = useState({});
return (
<form onSubmit={handleSubmit}>
<label>Enter your name:
<input
type="text"
name="username"
value={inputs.username || ""}
onChange={handleChange}
/>
</label>
<label>Enter your age:
<input
type="number"
name="age"
value={inputs.age || ""}
onChange={handleChange}
/>
</label>
<input type="submit" />
</form>
)
}
Textarea
The textarea element in React is slightly different from ordinary HTML.
In HTML the value of a textarea was the text between the start
tag <textarea> and the end tag </textarea>.
<textarea>
Content of the textarea.
</textarea>
Example:
A simple textarea with some content:
function MyForm() {
const [textarea, setTextarea] = useState(
"The content of a textarea goes in the value attribute"
);
return (
<form>
<textarea value={textarea} onChange={handleChange} />
</form>
)
}
Select
A drop down list, or a select box, in React is also a bit different from HTML.
in HTML, the selected value in the drop down list was defined with
the selected attribute:
HTML:
<select>
<option value="Ford">Ford</option>
<option value="Volvo" selected>Volvo</option>
<option value="Fiat">Fiat</option>
</select>
In React, the selected value is defined with a value attribute on
the select tag:
Example:
A simple select box, where the selected value "Volvo" is initialized in the
constructor:
function MyForm() {
const [myCar, setMyCar] = useState("Volvo");
return (
<form>
<select value={myCar} onChange={handleChange}>
<option value="Ford">Ford</option>
<option value="Volvo">Volvo</option>
<option value="Fiat">Fiat</option>
</select>
</form>
)
React Hooks
Hooks were added to React in version 16.8.
Hooks allow function components to have access to state and other React
features. Because of this, class components are generally no longer
needed.
What is a Hook?
Hooks allow us to "hook" into React features such as state and lifecycle
methods.
Example:
Here is an example of a Hook. Don't worry if it doesn't make sense. We will
go into more detail in the next section.
function FavoriteColor() {
const [color, setColor] = useState("red");
return (
<>
<h1>My favorite color is {color}!</h1>
<button
type="button"
onClick={() => setColor("blue")}
>Blue</button>
<button
type="button"
Here we are using the useState Hook to keep track of the application state.
Hook Rules
There are 3 rules for hooks:
Custom Hooks
If you have stateful logic that needs to be reused in several components, you
can build your own custom Hooks.
Import useState
To use the useState Hook, we first need to import it into our component.
Example:
At the top of your component, import the useState Hook.
Initialize useState
We initialize our state by calling useState in our function component.
Example:
Initialize state at the top of the function component.
function FavoriteColor() {
const [color, setColor] = useState("");
}
Notice that again, we are destructuring the returned values from useState.
The second value, setColor, is the function that is used to update our state.
These names are variables that can be named anything you would like.
Read State
We can now include our state anywhere in our component.
Example:
Use the state variable in the rendered component.
function FavoriteColor() {
const [color, setColor] = useState("red");
Update State
To update our state, we use our state updater function.
We should never directly update state. Ex: color = "red" is not allowed.
Example:
Use a button to update the state:
function FavoriteColor() {
const [color, setColor] = useState("red");
return (
<>
<h1>My favorite color is {color}!</h1>
<button
type="button"
onClick={() => setColor("blue")}
>Blue</button>
</>
)
}
Example:
Create multiple state Hooks:
function Car() {
const [brand, setBrand] = useState("Ford");
const [model, setModel] = useState("Mustang");
const [year, setYear] = useState("1964");
const [color, setColor] = useState("red");
return (
<>
<h1>My {brand}</h1>
<p>
It is a {color} {model} from {year}.
</p>
</>
)
}
Example:
Create a single Hook that holds an object:
function Car() {
const [car, setCar] = useState({
brand: "Ford",
model: "Mustang",
year: "1964",
color: "red"
});
return (
<>
<h1>My {car.brand}</h1>
<p>
It is a {car.color} {car.model} from {car.year}.
</p>
</>
)
}
Example:
Use the JavaScript spread operator to update only the color of the car:
function Car() {
const [car, setCar] = useState({
brand: "Ford",
model: "Mustang",
year: "1964",
color: "red"
});
return (
<>
<h1>My {car.brand}</h1>
<p>
It is a {car.color} {car.model} from {car.year}.
</p>
<button
type="button"
onClick={updateColor}
>Blue</button>
</>
)
}
Some examples of side effects are: fetching data from API, directly updating
the DOM, and timers.
useEffect(<function>, <dependency>)
Example:
Use setTimeout() to count 1 second after initial render:
function Timer() {
useEffect(() => {
setTimeout(() => {
}, 1000);
});
root.render(<Timer />);
But wait!! It keeps counting even though it should only count once!
useEffect runs on every render. That means that when the count changes, a
render happens, which then triggers another effect.
This is not what we want. There are several ways to control when side effects
run.
1. No dependency passed:
useEffect(() => {
});
2. An empty array:
useEffect(() => {
}, []);
}, [prop, state]);
So, to fix this issue, let's only run this effect on the initial render.
Example:
Only run the effect on the initial render:
function Timer() {
const [count, setCount] = useState(0);
useEffect(() => {
setTimeout(() => {
setCount((count) => count + 1);
}, 1000);
}, []); // <- add empty brackets here
Example:
Here is an example of a useEffect Hook that is dependent on a variable. If
the count variable updates, the effect will run again:
function Counter() {
const [count, setCount] = useState(0);
const [calculation, setCalculation] = useState(0);
useEffect(() => {
setCalculation(() => count * 2);
}, [count]); // <- add the count variable here
return (
<>
<p>Count: {count}</p>
<button onClick={() => setCount((c) => c + 1)}>+</button>
<p>Calculation: {calculation}</p>
</>
);
}
Effect Cleanup
Some effects require cleanup to reduce memory leaks.
Timeouts, subscriptions, event listeners, and other effects that are no longer
needed should be disposed.
Example:
Clean up the timer at the end of the useEffect Hook:
function Timer() {
const [count, setCount] = useState(0);
useEffect(() => {
let timer = setTimeout(() => {
setCount((count) => count + 1);
}, 1000);
It can be used together with the useState Hook to share state between deeply
nested components more easily than with useState alone.
The Problem
State should be held by the highest parent component in the stack that
requires access to the state.
To do this without Context, we will need to pass the state as "props" through
each nested component. This is called "prop drilling".
Example:
Passing "props" through nested components:
function Component1() {
const [user, setUser] = useState("Jesse Hall");
return (
<>
<h1>{`Hello ${user}!`}</h1>
<Component2 user={user} />
</>
);
}
The Solution
The solution is to create context.
Create Context
To create context, you must Import createContext and initialize it:
Next we'll use the Context Provider to wrap the tree of components that need
the state Context.
Context Provider
Wrap child components in the Context Provider and supply the state value.
function Component1() {
const [user, setUser] = useState("Jesse Hall");
return (
<UserContext.Provider value={user}>
<h1>{`Hello ${user}!`}</h1>
<Component2 user={user} />
</UserContext.Provider>
);
}
Now, all components in this tree will have access to the user Context.
function Component5() {
const user = useContext(UserContext);
return (
<>
<h1>Component 5</h1>
<h2>{`Hello ${user} again!`}</h2>
</>
);
}
Full Example
Example:
Here is the full example using React Context:
function Component1() {
const [user, setUser] = useState("Jesse Hall");
return (
<UserContext.Provider value={user}>
<h1>{`Hello ${user}!`}</h1>
<Component2 user={user} />
</UserContext.Provider>
);
}
function Component2() {
return (
<>
<h1>Component 2</h1>
<Component3 />
</>
);
}
function Component3() {
return (
<>
<h1>Component 3</h1>
<Component4 />
</>
);
}
function Component4() {
return (
<>
<h1>Component 4</h1>
<Component5 />
</>
);
}
function Component5() {
const user = useContext(UserContext);
return (
<>
<h1>Component 5</h1>
<h2>{`Hello ${user} again!`}</h2>
</>
);
}
It can be used to store a mutable value that does not cause a re-render
when updated.
Example:
Use useRef to track application renders.
function App() {
const [inputValue, setInputValue] = useState("");
const count = useRef(0);
useEffect(() => {
count.current = count.current + 1;
});
return (
<>
<input
type="text"
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
/>
<h1>Render Count: {count.current}</h1>
</>
);
}
It's like doing this: const count = {current: 0}. We can access the count
by using count.current.
Run this on your computer and try typing in the input to see the application
render count increase.
But there are some instances where useRef can be used without causing
issues.
Example:
Use useRef to focus the input:
function App() {
const inputElement = useRef();
return (
<>
<input type="text" ref={inputElement} />
<button onClick={focusInput}>Focus Input</button>
</>
);
}
Example:
Use useRef to keep track of previous state values:
function App() {
const [inputValue, setInputValue] = useState("");
const previousInputValue = useRef("");
useEffect(() => {
previousInputValue.current = inputValue;
}, [inputValue]);
return (
<>
<input
type="text"
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
/>
<h2>Current Value: {inputValue}</h2>
<h2>Previous Value: {previousInputValue.current}</h2>
</>
);
}
In the useEffect, we are updating the useRef current value each time
the inputValue is updated by entering text into the input field.
If you find yourself keeping track of multiple pieces of state that rely on
complex logic, useReducer may be useful.
Syntax
useReducer(<reducer>, <initialState>)
Example:
import { useReducer } from "react";
import ReactDOM from "react-dom/client";
const initialTodos = [
{
id: 1,
title: "Todo 1",
complete: false,
},
{
id: 2,
title: "Todo 2",
complete: false,
},
];
function Todos() {
const [todos, dispatch] = useReducer(reducer, initialTodos);
return (
<>
{todos.map((todo) => (
<div key={todo.id}>
<label>
<input
type="checkbox"
checked={todo.complete}
onChange={() => handleComplete(todo)}
/>
{todo.title}
</label>
</div>
))}
</>
);
}
This is just the logic to keep track of the todo complete status.
All of the logic to add, delete, and complete a todo could be contained within
a single useReducer Hook by adding more actions.
This allows us to isolate resource intensive functions so that they will not
automatically run on every render.
The useCallback Hook only runs when one of its dependencies update.
The useCallback and useMemo Hooks are similar. The main difference is
that useMemo returns a memoized value and useCallback returns a
Problem
One reason to use useCallback is to prevent a component from re-rendering
unless its props have changed.
In this example, you might think that the Todos component will not re-render
unless the todos change:
Example:
index.js
return (
<>
<Todos todos={todos} addTodo={addTodo} />
<hr />
<div>
Count: {count}
<button onClick={increment}>+</button>
</div>
</>
);
};
Todos.js
import { memo } from "react";
You will notice that the Todos component re-renders even when the todos do
not change.
Why does this not work? We are using memo, so the Todos component should
not re-render since neither the todos state nor the addTodo function are
changing when the count is incremented.
Solution
To fix this, we can use the useCallback hook to prevent the function from
being recreated unless necessary.
Use the useCallback Hook to prevent the Todos component from re-
rendering needlessly:
Example:
index.js
return (
<>
<Todos todos={todos} addTodo={addTodo} />
<hr />
<div>
Count: {count}
<button onClick={increment}>+</button>
</div>
</>
);
};
The useMemo Hook only runs when one of its dependencies update.
The useMemo and useCallback Hooks are similar. The main difference is
that useMemo returns a memoized value and useCallback returns a
memoized function. You can learn more about useCallback in
the useCallback chapter.
Performance
The useMemo Hook can be used to keep expensive, resource intensive
functions from needlessly running.
When changing the count or adding a todo, you will notice a delay in
execution.
Example:
A poor performing function. The expensiveCalculation function runs on
every render:
return (
<div>
<div>
<h2>My Todos</h2>
{todos.map((todo, index) => {
return <p key={index}>{todo}</p>;
})}
<button onClick={addTodo}>Add Todo</button>
</div>
<hr />
<div>
Count: {count}
<button onClick={increment}>+</button>
<h2>Expensive Calculation</h2>
{calculation}
</div>
</div>
);
};
Use useMemo
To fix this performance issue, we can use the useMemo Hook to memoize
the expensiveCalculation function. This will cause the function to only run
when needed.
In the following example, the expensive function will only run when count is
changed and not when todo's are added.
Example:
Performance example using the useMemo Hook:
return (
<div>
<div>
<h2>My Todos</h2>
{todos.map((todo, index) => {
return <p key={index}>{todo}</p>;
})}
<button onClick={addTodo}>Add Todo</button>
</div>
<hr />
<div>
Count: {count}
<button onClick={increment}>+</button>
<h2>Expensive Calculation</h2>
{calculation}
</div>
</div>
);
};
}
return num;
};
Build a Hook
In the following code, we are fetching data in our Home component and
displaying it.
We will use the JSONPlaceholder service to fetch fake data. This service is
great for testing applications when there is no existing data.
Use the JSONPlaceholder service to fetch fake "todo" items and display the
titles on the page:
Example:
index.js:
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/todos")
.then((res) => res.json())
.then((data) => setData(data));
}, []);
return (
<>
{data &&
data.map((item) => {
return <p key={item.id}>{item.title}</p>;
})}
</>
);
};
Example:
useFetch.js:
useEffect(() => {
fetch(url)
.then((res) => res.json())
.then((data) => setData(data));
}, [url]);
return [data];
};
return (
<>
{data &&
data.map((item) => {
return <p key={item.id}>{item.title}</p>;
})}
</>
);
};
Example Explained
We have created a new file called useFetch.js containing a function
called useFetch which contains all of the logic needed to fetch our data.
We removed the hard-coded URL and replaced it with a url variable that can
be passed to the custom Hook.
In index.js, we are importing our useFetch Hook and utilizing it like any
other Hook. This is where we pass in the URL to fetch data from.
Now we can reuse this custom Hook in any component to fetch data from
any URL.