0% found this document useful (0 votes)
57 views

React Course

Uploaded by

Arken Maatoug
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
57 views

React Course

Uploaded by

Arken Maatoug
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 98

Chapter 0 : Web Pages

I. Introduction
Web pages are text files that allow the browser to display rich interfaces to the user:

- To visualize web pages, we need a browser (Chrome, Firefox, Opera, Internet Explorer, etc.).
- To write web pages, we need a text editor (visual studio code, notepad, atom, sublime text, etc.)

Web pages are created using 3 programming languages:

- HyperText Markup Language (HTML): indicates to the browser what elements should be
included in the webpage (and in what order).
- Cascading Style Sheets (CSS): indicates how each HTML element should be styled.
- JavaScript (JS): manipulates HTML elements programmatically on the browser in response to
actions by the end user.

Web pages can be served remotely by a web server or saved locally on the user device.

Web pages are HTML documents


- They can be stored in HTML files (files with “html” extension)
- They can include additional css and javascript files (css and js extensions)

Web pages can serve static or dynamic content:

- The content of static pages does not change over time


- The content of dynamic pages can change based on different parameters: the user role, the user
identity, the available data in the database, etc.

Types of dynamic web pages:

- Client-side rendered pages : the page content is created directly in the browser using JavaScript.
All logic, data fetching, templating and routing are handled on the client rather than the server.
- Server-Side Rendered pages : the page content is created on the web server, then served to the
client. Such pages, are written using languages that run on the server such as PHP, Java and ASP.
- Server-Side + Client-side rendered pages : the page content is created on the server and in the
browser.

1
II. HTML

Reference: https://www.w3schools.com/html/html_intro.asp

1. Introduction

What is HTML?

- HTML stands for Hyper Text Markup Language


- HTML is the standard markup language for creating Web pages
- HTML describes the structure of a Web page
- HTML consists of a series of elements
- HTML elements tell the browser how to display the content
- HTML elements label pieces of content such as "this is a heading", "this is a paragraph", "this is a
link", etc.

A Simple HTML Document :

<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
</head>
<body>
<h1>My First Heading</h1>
<p>My first paragraph.</p>
</body>
</html>

Example Explained

- The <!DOCTYPE html> declaration defines that this document is an HTML5 document
- The <html> element is the root element of an HTML page
- The <head> element contains meta information about the HTML page
- The <title> element specifies a title for the HTML page (which is shown in the browser's title
bar or in the page's tab)
- The <body> element defines the document's body, and is a container for all the visible contents,
such as headings, paragraphs, images, hyperlinks, tables, lists, etc.
- The <h1> element defines a large heading
- The <p> element defines a paragraph

2
2. Element syntax

An HTML element is defined by a start tag, some attributes, some content, and an end tag. The HTML
element is everything from the start tag to the end tag:

<tagname attribute1="val1" attribute2="val2">Content goes here...</tagname>

Examples of some HTML elements:

<h1>My First Heading</h1>

<p>My first paragraph.</p>

<p title="introduction" style="color:red;">


This is a short <strong>paragraph</strong> with <br>a line break.
</p>

Example 1:

Element:

<p>My first paragraph.</p>

Start tag: <p>


Element content: My first paragraph.
End tag: </p>

Example 2:

Element:

<p title="introduction" style="color:red;">


This is a short <strong>paragraph</strong> with <br>a line break.
</p>

Start tag: <p title="introduction" style="color:red;">


Element content: This is a short <strong>paragraph</strong> with <br>a line
break.
End tag: </p>
Attribute 1: title
Attribute 2: style

3
3. Empty elements

Some HTML elements have no content. These elements are called empty elements or void elements.
Empty elements do not have an end tag!

Examples of empty elements in HTML : <br>, <hr>, <img>, <input>, <meta>

4. Nested HTML Elements

HTML elements can be nested (this means that elements can contain other elements).

All HTML documents consist of nested HTML elements.

The following example contains 7 HTML elements (<html>, <body>, <h1>, <p>, <p>, <strong> and <br>):

<!DOCTYPE html>
<html>
<body>
<h1>My First Heading</h1>
<p>My first paragraph.</p>
<p title="introduction" style="color:red;">
This is a short <strong>paragraph</strong> with <br>a line break.
</p>
</body>
</html>

5. Attributes

HTML attributes provide additional information about HTML elements.

- All HTML elements can have attributes


- Attributes provide additional information about elements
- Attributes are always specified in the start tag
- Attributes usually come in name/value pairs like: name="value"

Examples:

- The <a> tag defines a hyperlink. The href attribute specifies the URL of the page the link goes to.

<a href="https://www.w3schools.com">Visit W3Schools</a>

- The <img> tag is used to embed an image in an HTML page. The src attribute specifies the path
to the image to be displayed. The width and height attributes specify the width and height of
the image (in pixels). The alt attribute specifies an alternate text for an image, if the image for
some reason cannot be displayed.

<img src="nature.jpg" width="500" height="600" alt="Trees and river">

4
6. Comments

HTML comments are not displayed in the browser, but they can help document your HTML source code.

Comments can be added anywhere to the HTML source code by using the following syntax:

<!-- Write your comments here -->

Example:

<!-- This is a comment -->

<p>This is a paragraph.</p>
<!-- <p>This is another paragraph </p> -->

<!-- Remember to add more information here -->

III. HTML elements


Reference: https://www.w3schools.com/tags/

1. Headings

The <h1> to <h6> tags are used to define HTML headings.

<h1> defines the most important heading. <h6> defines the least important heading.

2. Paragraphs

The <p> tag defines a paragraph.

Browsers automatically add a single blank line before and after each <p> element.

3. Links

The <a> tag defines a hyperlink, which is used to link from one page to another.

The most important attribute of the <a> element is the href attribute, which indicates the link's
destination.

Example:

<a href="https://www.w3schools.com">Visit W3Schools.com!</a>

5
4. Images

The <img> tag is used to embed an image in an HTML page.

Images are not technically inserted into a web page; images are linked to web pages. The <img> tag
creates a holding space for the referenced image.

The <img> tag has two required attributes:

 src - Specifies the path to the image

 alt - Specifies an alternate text for the image, if the image for some reason cannot be displayed

Note: Also, always specify the width and height of an image. If width and height are not specified, the
page might flicker while the image loads.

Example:

<img src="nature.jpg" width="500" height="600" alt="Trees and river">

5. Tables

The <table> tag defines an HTML table.

An HTML table consists of one <table> element and one or more <tr>, <th>, and <td> elements.

The <tr> element defines a table row, the <th> element defines a table header, and the <td> element
defines a table cell.

An HTML table may also include <caption>, <colgroup>, <thead>, <tfoot>, and <tbody> elements.

Example: Result:
<table border="1">
<tr>
<th>Month</th>
<th>Savings</th>
</tr>
<tr>
<td>January</td>
<td>$100</td>
</tr>
<tr>
<td>February</td>
<td>$80</td>
</tr>
</table>

6
6. Inputs

The <input> tag specifies an input field where the user can enter data.

The <input> element can be displayed in several ways, depending on the type attribute.

The different input types are as follows:

 <input type="button">  <input type="password">


 <input type="checkbox">  <input type="radio">
 <input type="color">  <input type="range">
 <input type="date">  <input type="reset">
 <input type="datetime-local">  <input type="search">
 <input type="email">  <input type="submit">
 <input type="file">  <input type="tel">
 <input type="hidden">  <input type="text"> (default value)
 <input type="image">  <input type="time">
 <input type="month">  <input type="url">
 <input type="number">  <input type="week">

Example: Result:
<label>First name:</label>
<input type="text"
name="fname"><br><br>
<label>Last name:</label>
<input type="text"
name="lname"><br><br>

7. Textareas

The <textarea> tag defines a multi-line text input control.

The <textarea> element is often used in a form, to collect user inputs like comments or reviews.

A text area can hold an unlimited number of characters, and the text renders in a fixed-width font
(usually Courier).

The size of a text area is specified by the cols and rows attributes (or with CSS).

The name attribute is needed to reference the form data after the form is submitted (if you omit
the name attribute, no data from the text area will be submitted).

7
Example:

<label>Review of W3Schools:</label><br>
<textarea name="w3review" rows="4" cols="50">
At w3schools.com you will learn how to make a website. They offer free
tutorials in all web development technologies.
</textarea>

8. Select

The <select> element is used to create a drop-down list.

The <select> element is most often used in a form, to collect user input.

The name attribute is needed to reference the form data after the form is submitted (if you omit
the name attribute, no data from the drop-down list will be submitted).

The <option> tags inside the <select> element define the available options in the drop-down list.

Example: Result
<label>Choose a car:</label>
<select name="cars">
<option value="volvo">Volvo</option>
<option value="saab">Saab</option>
<option value="opel" selected>Opel</option>
<option value="audi">Audi</option>
</select>

9. Buttons

The <button> tag defines a clickable button.

Inside a <button> element you can put text (and tags like <i>, <b>, <strong>, <br>, <img>, etc.). That is
not possible with a button created with the <input> element!

8
Example:

<button type="button" onclick="alert('Hello world!')">Click Me!</button>

10. Forms

The <form> tag is used to create an HTML form for user input.

The <form> element can contain one or more of the following form elements:

 <input>  <optgroup>
 <textarea>  <fieldset>
 <button>  <label>
 <select>  <output>
 <option>

Example: Result:
<form action="/action_page.php">
<label>First name:</label>
<input type="text" name="fname" value="ali"><br>
<label>Last name:</label>
<input type="text" name="lname" value="dridi"><br>
<input type="submit" value="Submit">
</form>

Form attributes:

- action: Specifies where to send the form-data when a form is submitted


- method: Specifies the HTTP method to use when sending form-data. Possible values are “get”
and “post”. By default, the form is submitted using the HTTP GET method.
- Etc.

11. Lists

The <ol> tag defines an ordered list. An ordered list can be numerical or alphabetical.

The <ul> tag defines an unordered (bulleted) list.

The <li> tag is used to define each list item.

9
Example: Result:
<p>Ordered list:</p>
<ol>
<li>Coffee</li>
<li>Tea</li>
<li>Milk</li>
</ol>

<p>Unordered list:</p>
<ul>
<li>Coffee</li>
<li>Tea</li>
<li>Milk</li>
</ul>

12. Division

The <div> tag defines a division or a section in an HTML document.

The <div> tag is used as a container for HTML elements - which is then styled with CSS or manipulated
with JavaScript.

The <div> tag is easily styled by using the class or id attribute.

Any sort of content can be put inside the <div> tag!

Note: By default, browsers always place a line break before and after the <div> element.

Example 1:
<div style="border: 5px solid red; background-color: lightblue; text-align: center;"
<h2>This is a heading in a div element</h2>
<p>This is some text in a div element.</p>
</div>

Result:

10
Instead of styling the <div> element using the style attribute, we can create a CSS class and style the
<div> according to this CSS class using the class attribute.

Example:

<style>
.myDiv {
border: 5px solid red;
background-color: lightblue;
text-align: center;
}
</style>

<div class="myDiv">
<h2>This is a heading in a div element.</h2>
<p>This is some text in a div element.</p>
</div>

IV. CSS Style


The CSS code can be written in 3 places :

- In an HTML file, in the « style » attribute of an HTML element


- In the « style » element of an HTML file
- In an independent CSS file

Example 1 : CSS code in the « style » attribute of an HTML element

<!DOCTYPE html>
<html>
<head>
<title>Développement WEB</title>
</head>
<body>
<h1 style="color: blue; text-align: center;">Le code CSS</h1>
<p>Comment utiliser le code CSS dans l’attribut d’un élément HTML</p>
</body>
</html>

Example 2 : CSS code in the « style » element of an HTML file

<!DOCTYPE html>
<html>
<head>
<title>Développement WEB</title>
<style>
h1 {
color: blue;
text-align: center;
}
11
p {
font-family: verdana;
font-size: 20px;
}
</style>
</head>

<body>
<h1>Le code CSS</h1>
<p>Comment utiliser le code CSS dans une page HTML</p>
</body>
</html>

Example 3 : CSS code in an independent CSS file

File mystyle.css
h1 {
color: blue;
text-align: center;
}

p {
font-family: verdana;
font-size: 20px;
}

File index.html
<!DOCTYPE html>
<html>
<head>
<title>Développement WEB</title>
<link rel="stylesheet" href="assets/css/mystyle.css">
</head>
<body>
<h1>Le code CSS</h1>
<p>Comment utiliser les fichiers CSS dans une page HTML</p>
</body>
</html>

V. Javascript
The Javascript code can be written in 3 places :

- In an HTML file, in an attribute of an HTML element


- In the « script » element of an HTML file
- In an independent Javascript file

12
Example 1 : Javascript code in the « onClick » attribute of an HTML element

<!DOCTYPE html>
<html>
<head>
<title>Développement WEB</title>
</head>
<body>
<h1>Le code JavaScript </h1>
<button type="button" onclick="document.getElementById("demo").innerHTML=Date();">
Click to show Time.
</button>
<p id="demo"></p>
</body>
</html>

Example 2 : Javascript code in the « script » element of an HTML file

<!DOCTYPE html>
<html>
<head>
<title>Développement WEB</title>
<script>
function myFunction() {
document.getElementById("demo").innerHTML = Date();
}
</script>
</head>

<body>
<h1>Le code JavaScript </h1>
<button type="button" onclick="myFunction()">Click to show Time.</button>
<p id="demo"></p>
</body>
</html>

Exemple 3 : Javascript code in an independent Javascript file

File myscript.js
function myFunction() {
document.getElementById("demo").innerHTML = Date();
}

File index.html
<!DOCTYPE html>
<html>
<head>
<title>Développement WEB</title>
<script src="assets/js/myscript.js"></script>
13
</head>
<body>
<h1>Le code JavaScript </h1>
<button type="button" onclick="myFunction()">Click to show Time.</button>
<p id="demo"></p>
</body>
</html>

VI. Bootstrap Framework


Bootstrap is the most popular HTML, CSS, and JavaScript framework for developing responsive, mobile-
first websites.

Bootstrap 5.3 is the newest version of Bootstrap: https://getbootstrap.com/docs/5.3/getting-


started/introduction/

Two methods to use Bootstrap:

- Download Bootstrap files and include them in HTML documents.


- Include Bootstrap files from the CDN (Content Delivery Network) links.

Example: Include Bootstrap from CDN links:

<!doctype html>
<html lang="en">
<head>
<title>Bootstrap demo</title>
<link href="https://cdn.jsdelivr.net/npm/[email protected]
alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/[email protected]
alpha1/dist/js/bootstrap.bundle.min.js"></script>
</head>
<body>
<h1 class="rounded text-center bg-primary text-white p-3 m-3">Hello, world!</h1>
</body>
</html>

Result:

14
Chapter 1: About React.js

I. Introduction
What is React?

- React is a JavaScript library created by Facebook.


- React is used to build user interfaces  it is used for frontend development
- React is used to build single-page applications.
- React allows us to create reusable UI components.

How does React Work?

- React creates a VIRTUAL DOM in memory: Instead of manipulating the browser's DOM directly,
React creates a virtual DOM in memory, where it does all the necessary manipulating, before
making the changes in the browser DOM.
- React only changes what needs to be changed: React finds out what changes have been made,
and changes only what needs to be changed.

React.JS History

- Current version of React.JS is 18.2.0 (June 14, 2022).


- Initial Release to the Public (V0.3.0) was in 2013.
- React.JS was first used in 2011 by Facebook.

Single Page Application:

- A single-page application is an application that loads a single HTML page (HTML file).
- Any interactions with the page do not require reloading the page.
- React can build a single-page application, and can be used to enhance existing websites.

Frontend vs Backend vs Full-stack :

- Frontend development refers to the client-side (how a web page looks).


- The basic languages for Frontend Development are HTML, CSS, and JavaScript.
- Backend development refers to the server-side (how a web page works).
- Full-stack development is to develop both client and server applications.

15
Popular Stacks:

- WAMP stack: Windows - Apache - MySQL - PHP


- XAMPP stack: cross-platform - Apache - MariaDB - PHP - Perl
- MEAN stack: MongoDB - Express - AngularJS - Node.js
- MERN stack: MongoDB - Express - ReactJS - Node.js

Web frameworks and technologies: (source https://survey.stackoverflow.co/2022)

- Node.js and React.js are the two most common web technologies used by Professional
Developers and those learning to code.
- Angular is used more by Professional Developers than those learning to code (23% vs 10%)
- ASP.NET (18.6%) and ASP.NET Core (14.9%) are widely used.

Most used web technologies (source https://survey.stackoverflow.co/2022)


16
II. Vocabulary (see https://reactjs.org/docs/glossary.html )

Javascript ES6: (see https://www.w3schools.com/js/js_es6.asp )

- ES6 is the most recent version of JavaScript.


- It is also known as ES2015
- It includes many additions to the previous versions such as: arrow functions, classes, template
literals, let and const statements.

Babel:

- Babel is a JavaScript compiler used with React.


- It takes JavaScript code, transforms it and returns JavaScript code in a different format.
- For example, it takes ES6 syntax and transforms it into syntax that older browsers are capable of
interpreting.

Bundlers:

- Bundlers take JavaScript and CSS code written as separate modules, and combine them together
into a few files better optimized for the browsers.
- Some bundlers commonly used in React applications include Webpack and Browserify.

Package Managers:

- Package managers are tools that allow you to manage dependencies in your project
- npm and Yarn are two package managers commonly used in React applications. Both of them
are clients for the same npm package registry at https://registry.npmjs.org

JSX: (see https://beta.reactjs.org/learn/writing-markup-with-jsx )

- JSX is a syntax extension to JavaScript that lets you write HTML-like markup inside a JavaScript
file  JSX allows us to put markup into JavaScript
- It is similar to HTML, but it has full power of JavaScript.
- JSX gets compiled into React.createElement() calls which return plain JavaScript objects called
“React elements”.
- Example:
<h1>Hello, world</h1>

17
Elements:

- React elements are the building blocks of React applications.


- One might confuse elements with a more widely known concept of “components”.
- An element describes what you want to see on the screen.
- Elements are not used directly, but get returned from components.
- Example:
const element = <h1>Hello, world</h1>;

Components:

- React components are small, reusable pieces of code that return a React element to be rendered
to the page.
- The simplest React component is a JavaScript function that returns a React element:

function Welcome() {
return <h1>Hello, world</h1>;
}

- Components can also be ES6 classes:

class Welcome extends React.Component {


render() {
return <h1>Hello, world</h1>;
}
}

Document Object Model (DOM):

- The DOM represents the web page as a tree structure. Any piece of HTML that we write is added
as a node, to this tree.
- With JavaScript, we can access any of these nodes (HTML elements) and update them. This
means that the DOM enables JavaScript to access and modify the web page easily.
- The root node of the DOM is “document”. JavaScript can access this variable in the browser.
- Any HTML tag you write is going to be a direct or indirect child of the root node “document”.

III. Setup
Requirements:

- Install Node.js : we need npm (node package manager) to install dependencies (required
libraries). Available at: https://nodejs.org/
- Install text editor: Visual Studio Code is recommended
18
Create a new React application called “my-app” :

npx create-react-app my-app


cd my-app
npm start

“create-react-app” package will install:

- The required dependencies of the new React application


- Lightweight Development Server
- Webpack for bundling the files
- Babel for compiling JavaScript code
- Etc.

Project structure:

Initial Project structure: Minimal Project structure:

19
“index.html” is the single page of the application

index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>

<div id="root"></div>

</body>
</html>

The div element having id=root is the container of the React application

“index.js” is the entry point of the application => JavaScript code of this file will be executed on loading
the html page in the browser.

index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';

const root = ReactDOM.createRoot(document.getElementById('root'));


root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);

reportWebVitals();
import React from 'react';
import ReactDOM from 'react-dom/client';

let element = <h1>Hello world!</h1>;

const root = ReactDOM.createRoot(document.getElementById('root'));


root.render(element);

20
Babel will convert the JSX syntax into a simple JavaScript code:

JSX syntax Simple JavaScript syntax


let element = <h1>Hello world!</h1>; let element = React.createElement(
"h1",
null,
"Hello world!"
);

IV. JSX (see https://reactjs.org/docs/jsx-in-depth.html )


1. Syntax

JSX is a syntax extension to JavaScript. It produces React “elements”.

React doesn’t require using JSX, but it is practical when creating UI inside the JavaScript code  easy to
convert html elements into React elements.

JSX and React are two separate things: JSX is a syntax extension, while React is a JavaScript library.

Simple JSX expression (React element):

let element = <h1>Hello, world!</h1>;

JSX expression on multiple lines:

Example 1: no parentheses Example 2: no parentheses


let element = let element = (
<h1> <h1>
Hello, world! Hello, world!
</h1> </h1>
; );

2. Embedding Expressions in JSX:

We can declare a variable called name and then use it inside JSX by wrapping it in curly braces:

const name = "Ali Dridi";


const element = <h1>Hello, {name}</h1>;

You can put any valid JavaScript expression inside the curly braces in JSX. For example, 2 + 2, x + y, and
formatName(user) are all valid JavaScript expressions.

21
Example: embed the result of calling a JavaScript function into an <h1> element

function formatName(user) {
return "******" + user + "******";
}

const element = (
<h1>
Hello {formatName("Ali Dridi")}
</h1>
);

Don’t put quotes around curly braces when embedding a JavaScript expression in an attribute. You
should either use quotes (for string values) or curly braces (for expressions), but not both in the same
attribute.

3. Specifying Attributes with JSX: (see https://beta.reactjs.org/learn/writing-markup-with-jsx )

let link = <a href="https://www.reactjs.org"> link </a>;

Since JSX is closer to JavaScript than to HTML, React elements use camelCase naming convention
instead of HTML attribute names. For example: tabindex attribute becomes tabIndex.

JSX attributes can’t contain dashes or be reserved words like class: class becomes className in JSX

For historical reasons, aria-* and data-* attributes are written as in HTML with dashes.

4. Specifying Children with JSX:

Unlike HTML elements, empty React elements must be closed. If a tag is empty, you may close it
immediately with />

Examples:

const element = <img src="https://picsum.photos/120/60"></img>;


const element = <img src="https://picsum.photos/120/60" />;

JSX tags may contain children:

Example 1: elements wrapped into a div Example 2: elements wrapped into a fragment
let element = ( let element = (
<div> <>
<h1>Hello, world!</h1> <h1>Hello, world!</h1>
<p>This is a simple paragraph</p> <p>This is a simple paragraph</p>
<p>Another paragraph</p> <p>Another paragraph</p>
</div> </>
); );
22
<></> is a shorter syntax for <React.Fragment></React.Fragment>

<></> creates a fragment. Fragments let you group a list of children without adding extra nodes to the
DOM (see https://reactjs.org/docs/fragments.htm ).

Exercise 1:

Convert the following HTML markup into a JSX element:

a) Example 1

<h1>Hello, world!</h1>
<p>This is a simple paragraph.</p>
<p>Another paragraph.</p>

b) Example 2

<h1>Hello, world!</h1>
<p>This is a paragraph with two lines:<br>
-Line 1<br>
-Line 2</p>

c) Example 3

<p>Please enter your name</p>


<input type="text" value="ali dridi"><br>
<button type="button">OK</button>

d) Example 4

<h1>About Ali Dridi</h1>


<img src="https://picsum.photos/120/60" alt="Ali" class="photo">
<ul>
<li>Invented new traffic lights
<li>Improved the spectrum technology
</ul>

e) Example 5

<div class="intro">
<h1>Welcome to my website!</h1>
</div>
<p class="summary">
You can find my thoughts here.
<br><br>
<b>And <i>pictures</b></i> of scientists!
</p>

Useful links:

- Rules to convert HTML to JSX, link: https://beta.reactjs.org/learn/writing-markup-with-jsx


- HTML to JSX converter: https://transform.tools/html-to-jsx
23
Exercise 2:

a) Create a new React application called “tp1”. What are the suggested commands when the
application is created ?
b) Open the new application using VS Code (or any other editor of your choice)
c) Start the server
d) Delete all files in the “src” folder except “index.js”
e) Delete useless statements from “index.js”, create a simple JSX element and render it into the
page.
f) Add bootstrap links to the html file “public/index.html”
g) Convert the following HTML element into a JSX element and render it into the page
<h1 class="rounded text-center bg-primary text-white p-3 m-3">
Hello, world!
</h1>

h) Convert the HTML markup of the following Bootstrap Navbar into a JSX element and render it
into the page:

i) Create the following item using HTML and bootstrap

j) Convert the item into JSX element and display it 4 times on a bootstrap row

24
V. Components
Useful links :

- https://reactjs.org/docs/components-and-props.html
- https://reactjs.org/docs/react-component.html

1. Principle

Components let you split the UI into independent, reusable pieces, and think about each piece in
isolation.

Components accept arbitrary inputs (called “props”) and return React elements describing what should
appear on the screen.

React lets you define components as classes or functions. Components defined as classes currently
provide more features.

2. Function and Class Components

The simplest way to define a component is to write a JavaScript function:

import React from 'react';

function Welcome() {
return <h1>Hello World!</h1>;
}

You can also use an ES6 class to define a component:

import React from 'react';

class Welcome extends React.Component {


render() {
return <h1>Hello World!</h1>;
}
}

Import Component :

import React, {Component} from 'react';

class Welcome extends Component {


render() {
return <h1>Hello World!</h1>;
}
}

25
Render user-defined components :

import React from 'react';


import ReactDOM from 'react-dom/client';

function Welcome() {
return <h1>Hello World!</h1>;
}

const element = <Welcome />;

const root = ReactDOM.createRoot(document.getElementById('root'));


root.render(element);

User-Defined vs Built-in Components:

- When an element type starts with a lowercase letter, it refers to a built-in component like <div>
or <span>
- User-Defined Components Must Be Capitalized
- Types that start with a capital letter like <Hello /> correspond to a component defined or
imported in a JavaScript file.

Example:

Wrong Correct
import React from 'react'; import React from 'react';

// Wrong! // Correct!
function hello() { function Hello() {
return <div>Hello World</div>; return <div>Hello World</div>;
} }

function HelloWorld() { function HelloWorld() {


// Wrong! React thinks <hello /> // Correct! React knows <Hello />
// is an HTML element : // is a component :
return <hello />; return <Hello />;
} }

3. Props

React components use “props” (which stands for properties) to communicate with each other. Every
parent component can pass some information to its child components by giving them props.

Props are the information that you pass to a JSX tag. For example, className, src, alt, width, and height
are some of the props you can pass to an <img>.

When React sees an element representing a user-defined component, it passes JSX attributes to this
component as a single object (called “props”).
26
 “props” can be the JSX attributes or the object that allows the component to read JSX attributes!
 A single JSX attribute is a prop

Read props inside a function component:

function Article(props) {
return (
<div className="m-2 p-2 border rounded">
<h1>{props.title}</h1>
<p>{props.content}</p>
<p className="text-muted">{props.date}</p>
</div>
);
}

Read props inside a class component:

class Article2 extends Component {


render() {
return (
<div className="m-2 p-2 border rounded">
<h1>{this.props.title}</h1>
<p>{this.props.content}</p>
<p className="text-muted">{this.props.date}</p>
</div>
);
}
}

Pass props to a component:

const element = (
<>
<h1>Hello World</h1>
<Article
title="Computers"
content="Computers are very useful"
date="10/02/2023"
/>
<Article2
title="Internet"
content="Internet has a good speed"
date="23/01/2023"
/>
</>
);

const root = ReactDOM.createRoot(document.getElementById('root'));


root.render(element);

27
Props are Read-Only: Whether you declare a component as a function or a class, it must never modify
its own props.

function Welcome(props) {

props.name = "Salah"; // Wrong!

return <h1>Hello, {props.name}</h1>;


}

const element = <Welcome name="Ali" />;

4. Importing and Exporting Components

Components are reusable: you can create components into different files

- Export components where they are created


- Import components where they should be used

There are two ways to export components with JavaScript:

- default exports and named exports


- you can use one or both of them in the same file
- A file can have no more than one default export, but it can have any number of named exports

Syntax Export statement Import statement


Default export default function Button() {} import Button from './button.js';
Named export function Button() {} import { Button } from
'./button.js';

When you write a default import, you can put any name you want after import. For example, you could
write import Something from './button.js' and it provides the same default export.

With named imports, the name has to match on both sides. That’s why they are called named imports!

Default export:

export default function Welcome(props) {


return <h1>Hello World</h1>;
}
export default class Welcome extends Component {
render() {
return <h1>Hello World</h1>;
}
}

28
Named export:

export function Welcome(props) {


return <h1>Hello World</h1>;
}
export class Welcome extends Component {
render() {
return <h1>Hello World</h1>;
}
}

Default import:

import Welcome from './home.js';


import Avatar from './components/profile.js';

Named import:

import {Welcome} from './home.js';


import {Header, Picture, Description} from './components/profile.js';

Default and named import:

import Profile, {Picture, Description} from './components/profile.js';

More details: https://beta.reactjs.org/learn/importing-and-exporting-components

5. Lifecycle

In applications with many components, it’s very important to free up resources taken by the
components when they are destroyed.

Mounting

These methods are called in the following order when an instance of a component is being created and
inserted into the DOM:

- constructor()
- render()
- componentDidMount()

29
Updating

An update can be caused by changes to props or state. These methods are called in the following order
when a component is being re-rendered:

- render()
- componentDidUpdate()

Unmounting

This method is called when a component is being removed from the DOM:

- componentWillUnmount()

We can declare special methods on the component class to run some code when a component mounts
and unmounts:

class Clock extends React.Component {

constructor() {
}

componentDidMount() {
}

componentWillUnmount() {
}

render() {
return (
<div>
<h1>Hello, world!</h1>
</div>
);
}
}

The constructor for a class component is called before the component is mounted. When implementing
the constructor for a class component, you should call super(props) before any other statement.
Otherwise, this.props will be undefined in the constructor.

To use this.props correctly in the constructor, we need to:

- Add the “props” object to the parameter


- Call the base constructor in the first statement
- Pass “props” to the base constructor: super(props)

30
Example:

export class CartItem extends Component {


constructor(props) {
super(props);
}

render() {
return (
<div>
<span className="border rounded m-2 p-2">{this.props.count}</span>
</div>
);
}
}

VI. ES6
Class overview

The body of a class is the part that is in curly brackets {}. This is where you define class properties (fields
and methods).

Class fields are declared without keywords such as const or let.

Fields can be declared with or without a default value. Fields without default values default to
undefined.

class Rectangle {
height = 0;
width;

constructor(height, width, color) {


this.height = height;
this.width = width;
this.color = color;
}

info() {
console.log("height: " + this.height);
console.log("width: " + this.width);
console.log("color: " + this.color);
}
}

let rec = new Rectangle(10, 20, "red");


rec.info();

31
VII. Handling Events
Handling events with React elements is very similar to handling events on DOM elements. There are
some syntax differences:

- React events are named using camelCase, rather than lowercase.


- With JSX you pass a function as the event handler, rather than a string.

Example:

In HTML In React
<button onclick="activateLasers()"> <button onClick={activateLasers}>
Activate Lasers Activate Lasers
</button> </button>

Another difference is that you cannot return false to prevent default behavior in React. You must call
preventDefault explicitly. For example, with plain HTML, to prevent the default form behavior of
submitting, you can write:

<form onsubmit="console.log('You clicked submit.'); return false">


<button type="submit">Submit</button>
</form>

In React, this could instead be:

function Form() {
function handleSubmit(e) {
e.preventDefault();
console.log('You clicked submit.');
}

return (
<form onSubmit={handleSubmit}>
<button type="submit">Submit</button>
</form>
);
}
Note: the parameter e of handleSubmit is a synthetic event and is passed automatically to the function.

Callback functions in Function components:

- The callback function is a function called when an event occurs.


- The callback function can be defined inside the function component
- The callback function is called without any prefix (no this keyword)
32
Callback functions in Class components

To use callback functions in class components we need to follow one or several steps:

Step 1 : define callback functions and pass them to React events (React events are JSX attributes)

export class CartItem extends Component {


addItem() {
console.log("Add Item Clicked ...");
}

render() {
return (
<div>
<button type="button" onClick={this.addItem}>+</button>
<span className="m-2 p-2">{this.props.count}</span>
</div>
);
}
}

Step 2: to increase/decrease the number of items, we need to define a field and to initialize it in the
constructor. To read the props in the constructor, we should pass it to the constructor and to the base
class.

export class CartItem extends Component {


constructor(props) {
super(props);
this.count = this.props.count;
}

addItem() {
console.log("Add Item Clicked ...");
}

render() {
return (
<div>
<button type="button" onClick={this.addItem}>+</button>
<span className="m-2 p-2">{this.count}</span>
</div>
);
}
}

By default, “this” keyword is undefined in the callback methods of class components. The callback
function cannot use global fields.

33
Step 3: Bind “this” reference to the callback function in the constructor.

export class CartItem extends Component {


constructor(props) {
super(props);
this.count = this.props.count;
this.addItem = this.addItem.bind(this);
}

addItem() {
this.count++;
console.log("Add - Total Items: " + this.count);
}

render() {
return (
<div>
<button type="button" onClick={this.addItem}>+</button>
<span className="m-2 p-2">{this.count}</span>
</div>
);
}
}

When we click on the button, “count” will increase by 1 and the new value will be shown on the
console. But the count in the span will not change.

State:

To update the count in the span we need to use this.state which is the component memory:

- this.state is initialized with an object of one or many properties. Example:


this.state = {name: "Ali Dridi"};
- We read the value of any property by adding its name to this.state (example: this.state.name)
- We update the value of any property using this.setState method. We provide the method with
an object that contains the new value of the propertie. Example:
this.setState( {name: "Ali Dridi"} )
- It is wrong to update the property value using this.state (this.state.name = "Ons Abid")

34
Step 4: Initialize this.state in the constructor, display this.state.property_name in the UI and update
the UI by calling this.setState

export class CartItem extends Component {


constructor(props) {
super(props);
//this.count = this.props.count;
let initialCount = Number(this.props.count);
this.state = {count: initialCount};
this.addItem = this.addItem.bind(this);
}

addItem() {
//this.count++;
let newCount = this.state.count + 1;
this.setState({count: newCount});
console.log("Add - Total Items: " + newCount);
}

render() {
return (
<div>
<button type="button" onClick={this.addItem}>+</button>
<span className="m-2 p-2">{this.state.count}</span>
</div>
);
}
}

Exercise 1:

a. Create a new class component called “CartItem”. This component requires 3 attributes: name
(the product name), price (the unit price) and count (the number of units). It renders the
following element:

b. Create 2 callback functions: addItem and subItem. addItem increases the number of units by 1.
subItem decreases the number of units by 1 only if the number of units is greater than 1. These
functions should update the number of units and the total price of the product.

35
Hooks: (see https://reactjs.org/docs/hooks-intro.html)

Hooks are a new addition in React 16.8. They let you use state and other React features in function
components without writing a class.

“useState” function is a React Hook that lets you add a state variable to your function component.

Syntax:

const [state, setState] = useState(initialState);


Where “state” if the variable that we can display in the UI, and “setState” is the method that updates
the value of “state”.

Call useState at the top level of your component to declare a state variable.

import { useState } from 'react';

function MyComponent() {
const [age, setAge] = useState(28);
const [name, setName] = useState('Taylor');
const [todos, setTodos] = useState(() => createTodos());
// ...

State in Class Component vs. in Function Component:

a. State initialization:

Class Component Function Component


this.state = {age: 28, name: "Ali"}; let [age, setAge] = useState(28);
let [name, setName] = useState('Ali');

b. State update:

Class Component Function Component


this.setState({age: 26, name: "Ons"}); setAge(26);
setName("Ons");

c. State display:

Class Component Function Component


<p>{this.state.age}</p> <p>{age}</p>
<p>{this.state.name}</p> <p>{name}</p>

36
Exercise 2:

a. Create a new function component called “CartItem2”. This component requires 3 attributes:
name (the product name), price (the unit price) and count (the number of units). It renders the
following element:

b. Create 2 callback functions: addItem and subItem. addItem increases the number of units by 1.
subItem decreases the number of units by 1 only if the number of units is greater than 1. These
functions should update the number of units and the total price of the product.

37
TP3
Useful link: https://reactjs.org/docs/forms.html

1. Create a new Function Component called “ContactForm” that renders the following element:

2. Create the following states: firstNameError, lastNameError, emailError, messageError. These


states are initially empty strings and are used to show any validation error of the required fields.
Error messages are displayed in span elements and look like the following figure:

3. Create a callback function for the Submit button called submitForm. This function checks that all
the required fields are filled and displays error messages below missing fields. It uses the created
states.
4. Create a callback function for the Clear button called clearForm. This function clears all the
fields, sets the subject to the first value and deletes any error message.

38
VIII. Client Side Routing
1. Introduction

In traditional websites, the browser requests a document from a web server, downloads and evaluates
CSS and JavaScript assets, and renders the HTML sent from the server. When the user clicks a link, it
starts the process all over again for a new page.

Client side routing allows your app to update the URL from a link click without making another request
for another document from the server. Instead, your app can immediately render some new UI and
make data requests with fetch to update the page with new information.

 This enables faster user experiences because the browser doesn't need to request an entirely
new document or re-evaluate CSS and JavaScript assets for the next page.

Client side routing:

- Allows adding multiple pages (or views) in React


- Is not built into React by default
- Requires the installation of an additional package

Example of React packages for client side routing:

- React Router: https://reactrouter.com/


9,526,671 downloads/week (https://www.npmjs.com/package/react-router-dom)
- React Navigation: https://reactnavigation.org/
710,232 downloads/week (https://www.npmjs.com/package/@react-navigation/native)
- Wouter: https://github.com/molefrog/wouter
21,894 downloads/week (https://www.npmjs.com/package/wouter)

2. React Router

See: https://reactrouter.com/en/main/start/overview

React Router is the standard library for client side routing with react:

- Once set up, you'll be able to navigate between multiple components within react, synchronized
to changing URL paths
- It works with the HTML5 history, allowing you to use the forward/backward arrows in the
browser

39
Install React Router:

npm i react-router-dom

Client side routing is enabled by creating a Router and linking to pages with "Link" elements.

- React Router supports several routers, such as BrowserRouter, MemoryRouter, HashRouter,


NativeRouter, StaticRouter, etc.
- <a href=""> elements must be replaced by <Link to=""> elements. Example:
Use: <Link className="nav-link" to="/contact">Contact</Link>
Instead of: <a className="nav-link" href="/contact">Contact</a>
- In react-router-dom, a <Link> renders an accessible <a> element with a real href that points to
the resource it's linking to.

Rendering a <Link> allows the user to change the URL when they click it. React Router will prevent the
browser's default behavior and tell the history to push a new entry into the history stack. The location
changes and the new matches will render.

Example 1: Add BrowserRouter, Routes and Route to index.js

import React from 'react';


import ReactDOM from "react-dom/client";

import { BrowserRouter, Routes, Route } from "react-router-dom";

import { Navbar, Footer } from "./pages/Layout";


import Home from "./pages/Home";
import Products from "./pages/Products";
import Contact from "./pages/Contact";
import NoPage from "./pages/NoPage";

function App() {
return (
<BrowserRouter>
<Routes>
<Navbar />
<Route path="/" element={<Home />} />
<Route path="/products" element={<Products />} />
<Route path="/contact" element={<Contact />} />
<Route path="*" element={<NoPage />} />
<Footer />
</Routes>
</BrowserRouter>
);
}

const root = ReactDOM.createRoot(document.getElementById('root'));


root.render(<App />);

40
Example 2: Use <Link> instead of <a>

export function Navbar() {


return (
<nav>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/products">Products</Link>
</li>
<li>
<Link to="/contact">Contact</Link>
</li>
<li>
<Link to="/test">test</Link>
</li>
</ul>
</nav>
);
}

IX. REST API


1. Introduction

See: https://www.tutorialspoint.com/restful/restful_web_services_tutorial.pdf

REST stands for REpresentational State Transfer. It is a web architecture that uses HTTP Protocol for
data communication.

REST architecture allows the client to perform CRUD (create, read, update and delete) operation on
data (called resources) using different HTTP methods.

In REST architecture, a REST Server simply provides access to resources and the REST client accesses and
consumes the resources. Each resource is identified by URIs (called endpoints).

REST uses various representations to represent a resource like JSON, Text and XML. JSON is now the
most popular format being used in Web Services.

HTTP Methods

The following HTTP methods are most commonly used in a REST based architecture.

- GET - Provides a read only access to a resource.


- POST - Used to create a new resource.
- PUT - Used to update an existing resource.
- DELETE - Used to remove a resource.
41
A REST Server should provide services on endpoints link the following:

example.com/products

HTTP Method URI Operation


GET example.com/products Read all products
GET example.com/products/3 Read product with id=3
POST example.com/products Create a new product
PUT example.com/products/3 Edit product with id=3
DELETE example.com/products/2 Delete product with id=2

To allow the React app to perform CRUD operation using HTTP requests, we need a REST API (also called
Web API):

- Create a web API using any backend technology: node.js, Laravel, ASP.NET, SpringBoot, etc.
- Use an existing REST API: https://openlibrary.org/developers/api,
https://developers.google.com/books/
- Use a fake REST API on a local server: https://github.com/typicode/json-server

3. JSON Server

JSON Server is a REST server that can be installed locally using npm. It offers a REST API with any
number of endpoints.

It is downloaded 228,165 times per week (https://www.npmjs.com/package/json-server)

Install:

npm i -g json-server

Create a db.json file with some data:

{
"messages": [
],
"posts": [
{ "id": 1, "title": "json-server", "author": "typicode" }
],
"comments": [
{ "id": 1, "body": "some comment", "postId": 1 }
],
"profile": { "name": "typicode" }
}

42
Start the server (from command prompt terminal) :

json-server --watch db.json --port 3004


About the server:

- If you make POST, PUT, PATCH or DELETE requests, changes will be saved to db.json file
- A POST, PUT or PATCH request should include a Content-Type: application/json header
to use the JSON in the request body. Otherwise it will return a 2XX status code, but without
changes being made to the data.

Routes

Based on the previous db.json file, here are all the default routes:

GET /posts
GET /posts/1
POST /posts
PUT /posts/1
PATCH /posts/1
DELETE /posts/1

Other useful functionalities: Filter, Paginate, Sort, Slice, Operators, Search, etc.

2. HTTP Client in Javascript

To make network requests, we need an HTTP Client in the browser. The most famous clients are:

- Fetch API: built-in API


- Axios: third-party library with 41,957,516 downloads/week (www.npmjs.com/package/axios)

Fetch API

See : https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch

Fetch is a built-in API, so we don't have to install or import anything. It's available in all modern
browsers.

43
A basic fetch request is really simple to set up. Have a look at the following code:

fetch('http://example.com/messages')
.then((response) => response.json())
.then((data) => console.log(data));

Here we are fetching a JSON file across the network and printing it to the console. The simplest use
of fetch() takes one argument — the path to the resource you want to fetch — and does not directly
return the JSON response body but instead returns a promise that resolves with a Response object.

The Response object, in turn, does not directly contain the actual JSON response body but is instead a
representation of the entire HTTP response. So, to extract the JSON body content from
the Response object, we use the json() method, which returns a second promise that resolves with the
result of parsing the response body text as JSON.

Example 1 : GET Request

fetch('http://localhost:3004/messages/')
.then((response) => response.json())
.then((data) => console.log(data));

Example 2 : POST Request

const data = {
firstname: "Ali",
lastname: "Dridi",
email: "[email protected]",
phone: "97888555",
subject: "Order Status",
message: "Dear Sir, Is there any news regarding my last order?"
};

fetch('http://localhost:3004/messages/', {
method: 'POST', // *GET, POST, PUT, DELETE, etc.
mode: 'cors', // no-cors, *cors, same-origin
cache: 'no-cache',
credentials: 'same-origin', // include, *same-origin, omit
headers: {
'Content-Type': 'application/json'
},
redirect: 'follow', // manual, *follow, error
referrerPolicy: 'no-referrer',
body: JSON.stringify(data)
})
.then((response) => response.json())
.then((data) => console.log(data));

44
Example 3 : PUT Request

const data = {
firstname: "Ali",
lastname: "Dridi",
email: "[email protected]",
phone: "97888555",
subject: "Order Status",
message: "new message"
};

fetch('http://localhost:3004/messages/' + id, {
method: 'PUT', // *GET, POST, PUT, DELETE, etc.
mode: 'cors', // no-cors, *cors, same-origin
cache: 'no-cache',
credentials: 'same-origin', // include, *same-origin, omit
headers: {
'Content-Type': 'application/json'
},
redirect: 'follow', // manual, *follow, error
referrerPolicy: 'no-referrer',
body: JSON.stringify(data)
})
.then((response) => response.json())
.then((data) => console.log(data));

Example 4 : DELETE Request

fetch('http://localhost:3004/messages/1', {
method: 'DELETE'
})
.then((response) => response.json())
.then((data) => console.log(data));

Axios

See : https://axios-http.com/docs/intro

Axios is a promise-based HTTP Client for node.js and the browser.

Axios is a third-party HTTP client library. It can be installed by using a CDN or package manager.

To use Axios from the CDN, we can add the following element to the html file:

<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>

45
TP4
1. Install React Router in the React App using the following command:
npm i react-router-dom
2. Create the “pages” folder under src and create the following files in the “pages” folder:
a. Layout.js : contains the Navbar and the Footer components of the application

b. Home.js: contains the Home component which renders the home page (route / ). This
page contains <h2>Home Page</h2>
c. Products.js: contains the Products component which renders the products page (route
/products ). This page contains <h2>Products Page</h2>
d. Contact.js: contains the Contact component which renders the contact page (route
/contact ). This page contains <h2>Contact Form</h2> and a contact form.

e. NoPage.js: contains the NoPage component which renders the error page (any route).
This page contains <h2>Undefined Page</h2> and a contact form.

46
3. Create the pages/admin/messages folder and add two files into this folder:
a. List.js: contains the List component which lists the stored messages on the REST server.
b. Details.js: contains the Details component which shows the details of a message on the
REST server.

4. Add Client side routing using <BrowserRouter>, <Routes>, <Route> and <Link> elements. Add
the following routes:
a. path="/" element=<Home />
b. path="/products" element=<Products />
c. path="/contact" element=<Contact />
d. path="/admin/messages" element=<List />
e. path="/admin/messages/details/*" element=<Details />
f. path="*" element=<NoPage />

5. All pages should contain the same Navbar and Footer

6. Install JSON Server using the following command:


npm i -g json-server

7. Create the db.json file (anywhere) and add the following data to the file:

{
"messages": [
],
"posts": [
{ "id": 1, "title": "json-server", "author": "typicode" }
],
"comments": [
{ "id": 1, "body": "some comment", "postId": 1 }
],
"profile": { "name": "typicode" }
}

8. Start the server on port number 3004


json-server --watch db.json --port 3004

9. When the contact form is submitted, the callback function of the Submit button (called
submitForm) should submit an HTTP POST request to create a new message. Check the log data
on the browser console and check db.json file after submitting the form.

10. Complete the List component. It should read the messages from the JSON server and list them
into a table. Each table row allows the Admin to see the details and to delete a message.

47
11. Complete the Details component. It should display the details of a given message.

48
X. Conditional Rendering
See: https://reactjs.org/docs/conditional-rendering.html

In React, you can create distinct components that encapsulate behavior you need. Then, you can render
only some of them, depending on the state of your application.

Conditional rendering in React works the same way conditions work in JavaScript. Use JavaScript
operators like if or the conditional operator to create elements representing the current state, and let
React update the UI to match them.

Consider these two components:

function UserGreeting(props) {
return <h1>Welcome back!</h1>;
}

function GuestGreeting(props) {
return <h1>Please sign up.</h1>;
}

We’ll create a Greeting component that displays either of these components depending on whether a
user is logged in:

function Greeting(props) {
const isLoggedIn = props.isLoggedIn;
if (isLoggedIn) {
return <UserGreeting />;
}
return <GuestGreeting />;
}

const root = ReactDOM.createRoot(document.getElementById('root'));


// Try changing to isLoggedIn={true}:
root.render(<Greeting isLoggedIn={false} />);

Element Variables

You can use variables to store elements. This can help you conditionally render a part of the component
while the rest of the output doesn’t change. Example:

function LoginButton(props) {
return (
<button onClick={props.onClick}>Login</button>
);
}

function LogoutButton(props) {
return (
<button onClick={props.onClick}>Logout</button>
);
}

49
In the example below, we will create a stateful component called LoginControl.

It will render either <LoginButton /> or <LogoutButton /> depending on its current state. It will also
render a <Greeting /> from the previous example:

class LoginControl extends React.Component {


constructor(props) {
super(props);
this.handleLoginClick = this.handleLoginClick.bind(this);
this.handleLogoutClick = this.handleLogoutClick.bind(this);
this.state = {isLoggedIn: false};
}

handleLoginClick() {
this.setState({isLoggedIn: true});
}

handleLogoutClick() {
this.setState({isLoggedIn: false});
}

render() {
const isLoggedIn = this.state.isLoggedIn;
let button;
if (isLoggedIn) {
button = <LogoutButton onClick={this.handleLogoutClick} />;
} else {
button = <LoginButton onClick={this.handleLoginClick} />;
}

return (
<div>
<Greeting isLoggedIn={isLoggedIn} />
{button}
</div>
);
}
}

const root = ReactDOM.createRoot(document.getElementById('root'));


root.render(<LoginControl />);

While declaring a variable and using an if statement is a fine way to conditionally render a component,
sometimes you might want to use a shorter syntax. You can inline conditions in JSX, as explained below.

Inline If with Logical && Operator

You may embed expressions in JSX by wrapping them in curly braces. This includes the JavaScript logical
&& operator. It can be handy for conditionally including an element:

50
function Mailbox(props) {
const unreadMessages = props.unreadMessages;
return (
<div>
<h1>Hello!</h1>
{unreadMessages.length > 0 &&
<h2>
You have {unreadMessages.length} unread messages.
</h2>
}
</div>
);
}

const messages = ['React', 'Re: React', 'Re:Re: React'];

const root = ReactDOM.createRoot(document.getElementById('root'));


root.render(<Mailbox unreadMessages={messages} />);

It works because in JavaScript, true && expression always evaluates to expression, and false &&
expression always evaluates to false.

Therefore, if the condition is true, the element right after && will appear in the output. If it is false,
React will ignore and skip it.

Note that returning a falsy expression will still cause the element after && to be skipped but will return
the falsy expression. In the example below, <div>0</div> will be returned by the render method.

render() {
const count = 0;
return (
<div>
{count && <h1>Messages: {count}</h1>}
</div>
);
}

Inline If-Else with Conditional Operator

Another method for conditionally rendering elements inline is to use the JavaScript conditional operator
condition ? true : false.

51
In the example below, we use it to conditionally render an element.

render() {
const isLoggedIn = this.state.isLoggedIn;
return (
<div>
{isLoggedIn
? <LogoutButton onClick={this.handleLogoutClick} />
: <LoginButton onClick={this.handleLoginClick} />
}
</div>
);
}

Preventing Component from Rendering

In rare cases you might want a component to hide itself even though it was rendered by another
component. To do this return null instead of its render output.

In the example below, the <WarningBanner /> is rendered depending on the value of the prop called
warn. If the value of the prop is false, then the component does not render:

function WarningBanner(props) {
if (!props.warn) {
return null;
}

return (
<div>
Warning!
</div>
);
}

function Page() {
const [warning, showWarning] = useState(true);

return (
<div>
<WarningBanner warn={warning} />
<button onClick={() => showWarning(!warning)}>
{warning ? 'Hide' : 'Show'}
</button>
</div>
);
}

const root = ReactDOM.createRoot(document.getElementById('root'));


root.render(<Page />);

52
TP 5
1. Create a new file called “AdminProducts.js” under “src\pages\admin”. This file contains 4
components: AdminProducts, ProductList, CreateProduct and EditProduct.
2. AdminProducts is rendered on the following URL: “/admin/products”.
3. The AdminProducts component renders either a list of products (ProductList component) or a
Create Product form (CreateProduct component) or an Edit Product form (EditProduct):
a. If the user clicks on “List” button, AdminProducts renders ProductList element
b. If the user clicks on “Create” button, AdminProducts renders CreateProduct element
c. If the user clicks on “Edit” button, AdminProducts renders EditProduct element

export function AdminProducts() {


const [listProducts, setListProducts] = useState([
{ id: 1, name: "Samsung 11E", description: "smartphone", price: "600$" },
{ id: 2, name: "iPhone 14", description: "Black iPhone", price: "800$" },
{ id: 3, name: "Nokia 300E", description: "Simple phone", price: "100$" },
{ id: 4, name: "HP Envy 10A", description: "Grey color", price: "750$" },
]);

const [content, setContent] = useState("list");

let ui = null;
if (content === "list") {
ui = (
<ProductList products={listProducts} />
);
}
else if (content === "create") {
ui = (
<CreateProduct />
);
}

return (
<div className="container">
<button type="button" onClick={() => setContent("list")}>List</button>
<button type="button" onClick={() => setContent("create")}>Create</button>
<br />

{ui}
</div>
);
}

function CreateProduct() {
return (
<>
<h2 className="text-center mb-3">Create New Product</h2>
</>
);
}

function EditProduct(props) {
return (
<>
<h2 className="text-center mb-3">Edit Product {props.product.name}</h2>
</>
);
}

53
function ProductList(props) {
return (
<>
<h2 className="text-center mb-3">List Products</h2>
<table className="table">
<thead>
<tr>
<th>Name</th>
<th>Description</th>
<th>Price</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{
props.products.map((item, index) => {
return (
<tr key={index}>
<td>{item.name}</td>
<td>{item.description}</td>
<td>{item.price}</td>
<td>
<button type="button" className="me-3">Edit</button>
<button type="button">Delete</button>
</td>
</tr>
);
})
}

</tbody>
</table>
</>
);
}

4. CreateProduct should display a form that allow the admin to create a new product on the REST
server. Complete CreateProduct and create a form with the following fields: Name, Category,
Description, Manufacturer, Price. The form has 2 buttons; the submit button sends an HTTP
POST request to the server to create a new product. The cancel button hides the CreateProduct
and shows the ProductList.

5. ProductList reads the products from the server and shows them into a table. Each product in the
table has 2 buttons, the Edit button hides the ProductList and shows EditProduct component.
The delete button deletes the product from the server and refreshes the list of products.

6. EditProduct should display a form that allow the admin to edit a product on the REST server.
Complete EditProduct and create a form with the following fields: Name, Category, Description,
Manufacturer, Price. The form has 2 buttons; the submit button sends an HTTP POST request to
the server to update the product. The cancel button hides EditProduct and shows ProductList.

54
XI. Controlled and Uncontrolled Components
Uncontrolled components are independent components that maintain their own state and update it
based on user input.

Controlled components rise events to their controller component (the parent component), and the
controller component handles the event:

Controller Component (Parent Component)

onDelete() handleDelete()

Controlled Component (Child Component)

Uncontrolled Form:

export function Home() {


function handleSubmit(event) {
event.preventDefault();

// read form data


const formData = new FormData(event.target);

// convert formData to object


const user = Object.fromEntries(formData.entries());

// form validation
if (!user.firstname || !user.lastname) {
console.log("Please provide all the required fields!");
return;
}

console.log("Hello " + user.firstname);


}

return (
<form onSubmit={(event) => handleSubmit(event)}>
<label>First Name:</label>
<input type="text" name="firstname" defaultValue="Ali" />
<label>Last Name:</label>
<input type="text" name="lastname" defaultValue="Dridi" />
<button type="submit">Submit</button>
</form>
);
}

55
Controlled Form:

export function Home() {


const [user, setUser] = useState({firstname: "Ali", lastname: "Dridi"});

function handleChange(event) {
setUser({...user, [event.target.name]: event.target.value});
}

function handleSubmit(event) {
event.preventDefault();

// form validation
if (!user.firstname || !user.lastname) {
console.log("Please provide all the required fields!");
return;
}

console.log("Hello " + user.firstname);


}

return (
<form onSubmit={(event) => handleSubmit(event)}>
<label>First Name:</label>
<input type="text" name="firstname"
value={user.firstname}
onChange={(event) => handleChange(event)} />

<label>Last Name:</label>
<input type="text" name="lastname"
value={user.lastname}
onChange={(event) => handleChange(event)} />

<button type="submit">Submit</button>
</form>
);
}

Pros and Cons

Useful links:

- Uncontrolled Components: https://reactjs.org/docs/uncontrolled-components.html


- Controlled Components: https://reactjs.org/docs/forms.html

56
Example of Controller/Controlled Components:

export function AdminProducts() {


const [content, setContent] = useState(<ProductList showForm={showForm} />);

function showList() {
setContent(<ProductList showForm={showForm} />);
}

function showForm(product) {
setContent(<ProductForm showList={showList} />);
}

return (
<div className="container my-5">
{content}
</div>

);
}

function ProductList(props) {
return (
<>
<h2 className="text-center mb-3">List Products</h2>
<button type="button"
onClick={() => props.showForm({})}>Create</button>
</>
);
}

function ProductForm(props) {
return (
<>
<h2 className="text-center mb-3">Create New Product</h2>
<button type="button"
onClick={() => props.showList({})}>Cancel</button>
</>
);
}

57
Chapter 2: Hooks

Link: https://react.dev/reference/react

I. Introduction
Hooks are functions that allow function components to have similar capabilities as class components.

They let you use React features from function components.

Hooks are a new addition in React 16.8

You can either use the built-in Hooks or combine them to build your own.

II. Built-in Hooks


1. State Hooks

State lets a component “remember” information like user input. For example, a form component can
use state to store the input value, while an image gallery component can use state to store the selected
image index.

To add state to a component, use one of these Hooks:

- useState declares a state variable that you can update directly.


- useReducer declares a state variable with the update logic inside a reducer function.

2. Context Hooks

Context lets a component receive information from distant parents without passing it as props. For
example, your app’s top-level component can pass the current UI theme to all components below, no
matter how deep.

- useContext reads and subscribes to a context.

3. Ref Hooks

Refs let a component hold some information that isn’t used for rendering, like a DOM node or a timeout
ID. Unlike with state, updating a ref does not re-render your component. Refs are an “escape hatch”
from the React paradigm. They are useful when you need to work with non-React systems.

- useRef declares a ref. You can hold any value in it, but most often it’s used to hold a DOM node.
- useImperativeHandle lets you customize the ref exposed by your component. It is rarely used.

58
4. Effect Hooks

Effects let a component connect to and synchronize with external systems. This includes dealing with
network, browser DOM, animations, widgets written using a different UI library, and other non-React
code.

- useEffect connects a component to an external system.

There are two rarely used variations of useEffect with differences in timing:

- useLayoutEffect fires before the browser repaints the screen. You can measure layout here.
- useInsertionEffect fires before React makes changes to the DOM. Libraries can insert dynamic
CSS here.

5. Performance Hooks

A common way to optimize re-rendering performance is to skip unnecessary work. For example, you
can tell React to reuse a cached calculation or to skip a re-render if the data has not changed since the
previous render.

To skip calculations and unnecessary re-rendering, use one of these Hooks:

- useMemo lets you cache the result of an expensive calculation.


- useCallback lets you cache a function definition before passing it down to an optimized
component.

To prioritize rendering, use one of these Hooks:

- useTransition marks a state transition as non-blocking and allow other updates to interrupt it.
- useDeferredValue defers updating a non-critical part of the UI and let other parts update first.

6. Other Hooks

These Hooks are mostly useful to library authors and aren’t commonly used in the application code.

- useDebugValue lets you customize the label React DevTools displays for your custom Hook.
- useId lets a component associate a unique ID with itself. Typically used with accessibility APIs.
- useSyncExternalStore lets a component subscribe to an external store.

7. Custom Hooks

https://react.dev/learn/reusing-logic-with-custom-hooks#extracting-your-own-custom-hook-from-a-
component
59
III. useContext
https://www.w3schools.com/react/react_usecontext.asp

React Context is a way to manage state globally.

It can be used together with useState to share state between deeply nested components more easily
than with useState alone.

1. useState alone example:

export default function Home() {


const [count, setCount] = useState(0);

return (
<>
<Total count={count} />
<hr />
<Component1 count={count} setCount={setCount} />
</>
);
}

function Total(props) {
return (<h1>Total: {props.count}</h1>);
}

function Component1(props) {
return (
<>
<h1>Component 1</h1>
<Product count={props.count} setCount={props.setCount} >
Product 1
</Product>
<Product count={props.count} setCount={props.setCount} >
Product 2
</Product>
</>
);
}

function Product(props) {
return (
<>
<h1>{props.children}</h1>
<button onClick={() => props.setCount(props.count + 1)}>
Add Product
</button>
</>
);
}

Even though Component1 did not need the state, it had to pass the state along to reach Product. This is
called "prop drilling".

60
2. useContext + useState

To share the state using React Context we need to

- Create Context using createContext


- Wrap child components in the Context Provider and supply the state value.
- Use the useContext Hook

Example 1 : Parent and child components in the same file

import React, { useState } from "react";


import { createContext, useContext } from "react";

const CountContext = createContext();

export default function Home() {


const [count, setCount] = useState(0);

return (
<CountContext.Provider value={{count, setCount}}>
<Total />
<hr />
<Component1 />
</CountContext.Provider>
);
}

function Total() {
const data = useContext(CountContext);
return (<h1>Total: {data.count}</h1>);
}

function Component1() {
return (
<>
<h1>Component 1</h1>
<Product >Product 1</Product>
<Product >Product 2</Product>
</>
);
}

function Product(props) {
const data = useContext(CountContext);

return (
<>
<h1>{props.children}</h1>
<button onClick={() => data.setCount(data.count + 1)}>
Add Product
</button>
</>
);
}

61
Example 2 : Parent and child components in different files

Create Context

CountContext.js
import { createContext } from "react";

export const CountContext = createContext();

Import Context in Parent component and Wrap child components

Home.js
import React, { useState } from "react";
import { Total } from "./Total";
import { Product } from "./Product";
import { CountContext } from "./CountContext";

export default function Home(props) {


const [count, setCount] = useState(0);

return (
<CountContext.Provider value={{count, setCount}}>
<Total />
<hr />
<Component1 />
</CountContext.Provider>
);
}

function Component1() {
return (
<>
<h1>Component 1</h1>
<Product >Product 1</Product>
<Product >Product 2</Product>
</>
);
}

Import Context in Child components and use the useContext Hook

Total.js
import React, { useContext } from "react";
import { CountContext } from "./CountContext";

export function Total() {


const data = useContext(CountContext);
return (<h1>Total: {data.count}</h1>);
}

62
Import Context in Child components and use the useContext Hook

Product.js
import React, { useContext } from "react";
import { CountContext } from "./CountContext";

export function Product(props) {


const data = useContext(CountContext);

return (
<>
<h1>{props.children}</h1>
<button onClick={() => data.setCount(data.count + 1)}>
Add Product
</button>
</>
);
}

IV. useRef
useRef is a React Hook that lets you reference a value that’s not needed for rendering.

Example:

import React from "react";


import { useRef } from "react";

function Home() {
let countRef = useRef(0);

function handleClick() {
countRef.current = countRef.current + 1;
console.log('You clicked ' + countRef.current + ' times!')
}

return (
<div className="container my-5">
<h2>Home Page</h2>
<button onClick={handleClick}>
Click me!
</button>
</div>
);
}

63
V. useEffect
https://react.dev/reference/react/useEffect

useEffect is a React Hook that lets you synchronize a component with an external system.

useEffect(setup, dependencies?)

Parameters

- setup: The function with your Effect’s logic. Your setup function may also optionally return a
cleanup function. When your component is first added to the DOM, React will run your setup
function. After every re-render with changed dependencies, React will first run the cleanup
function (if you provided it) with the old values, and then run your setup function with the new
values. After your component is removed from the DOM, React will run your cleanup function
one last time.
- optional dependencies: The list of all reactive values referenced inside of the setup code.
Reactive values include props, state, and all the variables and functions declared directly inside
your component body. If your linter is configured for React, it will verify that every reactive value
is correctly specified as a dependency. The list of dependencies must have a constant number of
items and be written inline like [dep1, dep2, dep3]. React will compare each dependency with its
previous value. If you omit this argument, your Effect will re-run after every re-render of the
component.

Returns : useEffect returns undefined.

Example 1 of 3: Passing a dependency array

If you specify the dependencies, your Effect runs after the initial render and after re-renders with
changed dependencies.

useEffect(() => {
// ...
}, [a, b]); // Runs again if a or b are different

64
Example 2 of 3: Passing an empty dependency array

If your Effect truly doesn’t use any reactive values, it will only run after the initial render.

useEffect(() => {
// ...
}, []); // Does not run again

Example 3 of 3: Passing no dependency array at all

If you pass no dependency array at all, your Effect runs after every single render (and re-render) of your
component.

useEffect(() => {
// ...
}); // Always runs again

65
Chapter 3: Client-side Data storage

Application data can be saved on the browser using 3 methods:

- Cookies
- Local Storage
- Session Storage

You can check the stored data on the browser using DevTools

66
I. Cookies

https://www.w3schools.com/js/js_cookies.asp

Cookies are data, stored in small text files, on your computer.

When a web server has sent a web page to a browser, the connection is shut down, and the server
forgets everything about the user.

Cookies were invented to solve the problem "how to remember information about the user":

- When a user visits a web page, his/her name can be stored in a cookie.
- Next time the user visits the page, the cookie "remembers" his/her name.

Cookies are saved in name-value pairs like:

username = John Doe

When a browser requests a web page from a server, cookies belonging to the page are added to the
request. This way the server gets the necessary data to "remember" information about users.

JavaScript can create, read, and delete cookies with the document.cookie property.

1. Create a Cookie with JavaScript

With JavaScript, a cookie can be created like this:

document.cookie = "username=John Doe";

You can also add an expiry date (in UTC time). By default, the cookie is deleted when the browser is
closed:

document.cookie = "username=John Doe; expires=Thu, 18 Dec 2013 12:00:00 UTC";

With a path parameter, you can tell the browser what path the cookie belongs to. By default, the cookie
belongs to the current page.

document.cookie = "username=John Doe; expires=Thu, 18 Dec 2013 12:00:00 UTC; path=/";

67
Example:

function setCookie(cname, cvalue, exdays) {


const d = new Date();
d.setTime(d.getTime() + (exdays*24*60*60*1000));
let expires = "expires="+ d.toUTCString();
document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
}

2. Read a Cookie with JavaScript

With JavaScript, cookies can be read like this:

let x = document.cookie;

The document.cookie property looks like a normal text string. But it is not.

document.cookie will return all cookies in one string much like: cookie1=value1; cookie2=value2;
cookie3=value3;

Even if you write a whole cookie string to document.cookie, when you read it out again, you can only
see the name-value pairs of it.

If you set a new cookie, older cookies are not overwritten. The new cookie is added to
document.cookie, so if you read document.cookie again you will get something like:

cookie1=value1; cookie2=value2; cookie3=value3; newcookie=value4;

If you want to find the value of one specified cookie, you must write a JavaScript function that searches
for the cookie value in the cookie string.

Example:

function getCookieValue(cookieName) {
// document.cookie contains all the cookies with the following format
// cookie1=value1; cookie2=value2; cookie3=value3;

let cookiesArray = document.cookie.split(';');


for (let i = 0; i < cookiesArray.length; i++) {
let cookie = cookiesArray[i];
if (cookie.includes(cookieName)) {
let name_value = cookie.split('=');
return name_value[1];
}
}

return "";
}

68
3. Change a Cookie with JavaScript

With JavaScript, you can change a cookie the same way as you create it:

document.cookie = "username=John Smith; expires=Thu, 18 Dec 2013 12:00:00 UTC; path=/";

The old cookie is overwritten.

4. Delete a Cookie with JavaScript

Deleting a cookie is very simple. You don't have to specify a cookie value when you delete a cookie.

Just set the expires parameter to a past date:

document.cookie = "username=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";

II. Web Storage API


https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API

1. Introduction

The Web Storage API provides mechanisms by which browsers can securely store key/value pairs.

Storage objects are simple key-value stores, similar to objects, but they stay intact through page loads.
The keys and the values are always strings (integer keys will be automatically converted to strings). You
can access these values like an object, or with the Storage.getItem() and Storage.setItem() methods.

The two mechanisms within Web Storage are as follows:

- sessionStorage maintains a separate storage area for each given origin that's available for the
duration of the page session (as long as the browser is open, including page reloads and
restores).
- localStorage does the same thing, but persists even when the browser is closed and reopened.

Note: sessionStorage is useless in React application because the application is able to maintain its data
during the page session (single page session)

69
2. Window localStorage

The localStorage object allows you to save key/value pairs in the browser.

Syntax: window.localStorage or just: localStorage

Save/Update Data in Local Storage

localStorage.colorSetting = "#a4509b";
localStorage["colorSetting"] = "#a4509b";
localStorage.setItem("colorSetting", "#a4509b");

Read Data from Local Storage

let lastname = localStorage.getItem("lastname");

Check if key exists

if (!localStorage.getItem("bgcolor")) {
localStorage.setItem("bgcolor", "blue");
}

Remove Data from Local Storage

//Remove by name
localStorage.removeItem(key);

//Remove All (Clear Local Storage)


localStorage.clear();

Save JavaScript Objects

const myObject = {
name : "john doe",
age : 32,
gender : "male",
profession : "optician"
}

localStorage.setItem("myObject", JSON.stringify(myObject));

Read JavaScript Objects

let data = localStorage.getItem("myObject");


const myObject = JSON.parse(data);
console.log(myObject);

70
TP 6

1) Add a shopping cart item to the navbar. It displays the number of units in the shopping cart and
allows the user to access the shopping cart details (displays the Cart component).

Use the following code:

// add bootstrap icon css to the document header


<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-
[email protected]/font/bootstrap-icons.css">

// add a ul element to the navbar


<ul className="navbar-nav">
<li className="nav-item">
<Link className="nav-link text-dark" to="/cart">
<i className="bi bi-cart4 text-danger h3"></i>
<span className="badge rounded-pill bg-danger"
style={{verticalAlign: "top"}}>
2
</span>
</Link>
</li>
</ul>

2) Create the Cart component that displays a page with the different products of the shopping cart.
The component allows:
a. Increasing/decreasing the number of products in the shopping cart
b. Removing a product from the shopping cart
c. Displaying the total price of the order
d. Displaying the total price of the different units of a single product
e. Updating the number of units in the shopping cart item of the navbar

(See example in the next page)

3) The application should initialize the shopping cart and save its data in the local storage.

71
72
Chapter 4: Authentication and Authorization

Links:

 http://assets.digitalocean.com/books/how-to-code-in-reactjs.pdf
 https://www.digitalocean.com/community/tutorials/how-to-add-login-authentication-to-react-
applications

1. Introduction
Web applications are a mix of public and private pages. Public pages are available to anyone, while a
private page requires a user login.

You can use authentication to manage which users are authorized to access which pages.

 Authentication verifies the identity of a user or service, and authorization determines their
access rights.

Which Comes First, Authentication or Authorization? As you cannot authorize a user before identifying
him, authentication always comes before authorization.

There are several authentication methods. The principal method is the authentication using JWT (JSON
Web Token):

- After successful authentication, the server sends a JWT to the client app
- The client app saves the JWT on the browser
- The client app includes the JWT to the requests that require the server authorization
- When the server receives a request that requires authorization, the server checks the validity of
the JWT before sending the response.

73
React applications need to :

- handle situations where a user tries to access a private page before they are authenticated
- save the login information (JWT) once users have successfully authenticated
- include the JWT to the requests sent to the server

2. JSON Web Token


JWT is composed of 3 parts separated by “.”: Header, Payload and Signature.

- Header: Identifies which algorithm is used to generate the signature


- Payload: Contains a set of claims. A claim is a key/value pair. The JWT specification defines
seven standard Claim Names: iss, sub, aud, exp, nbf, iat and jti. Custom claims can be included,
depending on the purpose of the token.
- Signature: Securely validates the token. The signature is calculated by encoding the header and
payload using Base64url and concatenating the two together with a “.” separator. That string is
then encrypted and hashed using the server secret and the algorithm specified in the header.
Signature = Sign(base64url(header) + "." + base64url(payload), server_secret)

74
Standard Claim Names:

Name Full Name Description


iss Issuer Identifies principal that issued the JWT.

sub Subject Identifies the subject of the JWT.

aud Audience Identifies the recipients that the JWT is intended for.
Expiration Identifies the expiration time on and after which the JWT must not be accepted for
exp
Time processing. The value must be a NumericDate.
Identifies the time on which the JWT will start to be accepted for processing. The
nbf Not Before
value must be a NumericDate.
iat Issued at Identifies the time at which the JWT was issued. The value must be a NumericDate.

jti JWT ID Case-sensitive unique identifier of the token even among different issuers.

Example:

Encoded JWT:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMTIiLCJuYW1lIjoiQWxpI
ERyaWRpIiwiZW1haWwiOiJhbGkuZHJpZGlAZ21haWwuY29tIiwiaWF0IjoxNTE2MjM5MDI
yLCJyb2xlIjoiYWRtaW4iLCJwaG9uZSI6IisyMTY5OTEyMzQ1NiIsImFkZHJlc3MiOiJNb
25hc3RpciwgVHVuaXNpYSJ9.vOnTPPsTUKbB73o2v0DwMh7pV7oTTaiHO37Ssgi2eCs

Decoded JWT:

Header
{
"alg": "HS256",
"typ": "JWT"
}
Payload
{
"sub": "112",
"name": "Ali Dridi",
"email": "[email protected]",
"iat": 1516239022,
"role": "admin",
"phone": "+21699123456",
"address": "Monastir, Tunisia"
}
Signature
HMACSHA256(base64Url(header) + "." + base64Url(payload), mystrongpassword123)

Test at https://jwt.io/

75
3. JSON Server Auth
Link: https://www.npmjs.com/package/json-server-auth

JSON Server Auth is an authentication module for JSON Server. It offers authentication & authorization
flow for your prototyping.

Install

npm i -g json-server json-server-auth

Create a db.json file with a users collection :

{
"users": []
}

Start JSON Server Auth:

json-server-auth db.json --port 3004

Register

Any of the following routes registers a new user :

POST /register
POST /signup
POST /users

email and password are required in the request body :

POST /register
{
"email": "[email protected]",
"password": "bestPassw0rd"
}

The password is encrypted by bcryptjs. The response contains the JWT access token (expiration time of
1 hour) :

201 Created
{
"accessToken": "xxx.xxx.xxx"
}
76
Any other property can be added to the request body:

POST /register
{
"email": "[email protected]",
"password": "bestPassw0rd",
"firstname": "Olivier",
"lastname": "Monge",
"age": 32
}

Update

Any update to an existing user (via PATCH or PUT methods) will go through the same process for email
and password.

Login

Any of the following routes logs an existing user in :

POST /login
POST /signin

email and password are required, of course :

POST /login
{
"email": "[email protected]",
"password": "bestPassw0rd"
}

The response contains the JWT access token (expiration time of 1 hour) :

200 OK
{
"accessToken": "xxx.xxx.xxx"
}

JWT payload

The access token has the following claims :

sub : the user id (as per the JWT specs).


email : the user email.

77
4. Authentication

Update the App component:

- Create a token state to store the token value and to check the authentication status
- Create new routes for the Register and Login components
- Share the token state and setToken with the Navbar, Register and Login components
function App() {
const [cartSize, setCartSize] = useState(0)
const [token, setToken] = useState("");

return (
<BrowserRouter>
<Navbar cartSize={cartSize} token={token} setToken={setToken} />

<Routes>
<Route path="/" element={<Home cartSize={cartSize} setCartSize={setCartSize} />} />
<Route path="/products" element={<Products />} />
<Route path="/contact" element={<Contact />} />

<Route path="/auth/register" element={<Register token={token} setToken={setToken} />} />


<Route path="/auth/login" element={<Login token={token} setToken={setToken} />} />

<Route path="/admin/products" element={<AdminProducts />} />


<Route path="/admin/messages" element={<List />} />
<Route path="/admin/messages/details/*" element={<Details />} />
<Route path="*" element={<NoPage />} />
</Routes>

<Footer />
</BrowserRouter>
);
}

Create the Register Component

- Check if the user is authenticated or not. If the user is authenticated, he will be redirected to “/”
- Sends the user details using POST method to JSON Server Auth at /register
- If the authentication is successful, save the token in the App token state

export function Register(props) {


if (props.token) {
return <Navigate to="/" />
}

function handleSubmit(event) {
event.preventDefault();

// read form data


const formData = new FormData(event.target);

// convert formData to object


const user = Object.fromEntries(formData.entries());

78
// register a new user
fetch("http://localhost:3004/register", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(user)
})
.then((response) => {
if (!response.ok) {
throw new Error("Network response was not OK");
}
return response.json()
})
.then((data) => {
console.log("Your new JWT is: ", data.accessToken)
props.setToken(data.accessToken)
})
.catch((error) => {
console.error("Error:", error);
});
}

return (
<div className="row">
<div className="col-lg-6 mx-auto">
<h2>Register Form</h2>

...
</div>
</div>
)
}

Update the Navbar:

- Use conditional rendering to add a UL to the Navbar: if the user is authenticated => show drop-
down list, otherwise => show Register/Login buttons
- Add Logout item => Logout allows the application to clear the JWT

export function Navbar(props) {


let ul = (
<ul className="navbar-nav">
<li className="nav-item dropdown">
<Link className="nav-link dropdown-toggle" to="/#" role="button"
data-bs-toggle="dropdown" aria-expanded="false">
Administrator
</Link>

79
<ul className="dropdown-menu">
<li><Link className="dropdown-item"
to="/admin/products">Products</Link></li>
<li><Link className="dropdown-item" to="/">Orders</Link></li>
<li><Link className="dropdown-item" to="/">Users</Link></li>
<li><Link className="dropdown-item"
to="/admin/messages">Messages</Link></li>
<li><hr className="dropdown-divider" /></li>
<li><Link className="dropdown-item" to="/#"
onClick={() => props.setToken("")}>Logout</Link></li>
</ul>
</li>
</ul>
)

if (!props.token) {
ul = (
<ul className="navbar-nav">
<li className="nav-item">
<Link className="btn btn-outline-primary me-2"
to="/Auth/Register">Register</Link>
</li>
<li className="nav-item">
<Link className="btn btn-primary" to="/Auth/Login">Login</Link>
</li>
</ul>

)
}

return (
<nav className="navbar navbar-expand-md py-3 mb-3">
<div className="container">
<Link className="navbar-brand" to="/">
Best Shop
</Link>
<button className="navbar-toggler" type="button" data-bs-toggle="collapse"
data-bs-target="#navbarNavDropdown" aria-controls="navbarNavDropdown" aria-
expanded="false" aria-label="Toggle navigation">
<span className="navbar-toggler-icon"></span>
</button>
<div className="collapse navbar-collapse" id="navbarNavDropdown">
<ul className="navbar-nav flex-grow-1">
<li className="nav-item">
<Link className="nav-link text-dark" to="/">Home</Link>
</li>
<li className="nav-item">
<Link className="nav-link text-dark" to="/products">Products</Link>
</li>
<li className="nav-item">
<Link className="nav-link text-dark" to="/contact">Contact</Link>
</li>
</ul>

{ul}

</div>
</div>
</nav>
);
}

80
TP 7

1. Install and run the JSON Server Auth


2. Create the Register component that displays the following form

3. Create the Login component that displays the following form

4. Update App component:


a. Create the token state
b. Add routes to Register and Login components
c. Share token/setToken with Navbar, Register and Login
81
5. Update Navbar component:
a. Use conditional rendering to display the Navbar

b. If the user clicks on the Logout item, he will be logged out (token will be deleted)

82
5. Authorization

a. Setup JSON Server Auth

Link: https://www.npmjs.com/package/json-server-auth

JSON Server Auth supports authorization and route protection.

To handle common use cases, JSON Server Auth draws inspiration from Unix filesystem permissions,
especialy the numeric notation.

 We add 4 for read permission.


 We add 2 for write permission.

Of course CRUD is not a filesystem, so we don't add 1 for execute permission.

Similarly to Unix, we then have three digits to match each user type :

 First digit are the permissions for the resource owner.


 Second digit are the permissions for the logged-in users.
 Third digit are the permissions for the public users.

For example, 640 means that only the owner can write the resource, logged-in users can read the
resource, and public users cannot access the resource at all.

The resource owner

A user is the owner of a resource if that resource has a userId property that matches his id property.

Example:

// The owner of
{ id: 8, text: 'blabla', userId: 1 }
// is
{ id: 1, email: '[email protected]' }

Private guarded routes will use the JWT sub claim (which equals the user id) to check if the user actually
owns the requested resource, by comparing sub with the userId property.

Except for the actual users collection, where the JWT sub claim must match the id property.

83
Guarded routes

Guarded routes exist at the root and can restrict access to any resource you put after them :

Route Resource permissions

User must be logged to write the resource.


664
Everyone can read the resource.

660 User must be logged to write or read the resource.

User must own the resource to write the resource.


644
Everyone can read the resource.

User must own the resource to write the resource.


640
User must be logged to read the resource.

600 User must own the resource to write or read the resource.

No one can write the resource.


444
Everyone can read the resource.

No one can write the resource.


440
User must be logged to read the resource.

No one can write the resource.


400
User must own the resource to read the resource.

Examples

 Public user (not logged-in) does the following requests :

Request Response

GET /664/posts 200 OK

POST /664/posts
401 UNAUTHORIZED
{text: 'hello'}

84
 Logged-in user with id: 1 does the following requests :

Request Response

GET /600/users/1
200 OK
Authorization: Bearer xxx.xxx.xxx

GET /600/users/23
403 FORBIDDEN
Authorization: Bearer xxx.xxx.xxx

Setup permissions

Of course, you don't want to directly use guarded routes in your requests. We can define permissions in
a configuration file.

Create a “routes.json” file :

{
"users": 600,
"messages": 640,
"products": 644
}

Start the server:

json-server-auth db.json --port 3004 -r routes.json

85
b. Client requests

During the authentication step, the client sends his email/password and receives 2 parameters from
JSON Server Auth: “accessToken” (JWT) and “user” (the user data object):

// login
fetch("http://localhost:3004/login", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(credentials)
})
.then((response) => {

if (response.ok) {
return response.json().then((data) => {
console.log("Your new JWT is: ", data.accessToken)
console.log("User datails: ", data.user)
props.updateTokenAndUser(data.accessToken, data.user)
})
}

//else
return response.text().then((data) => {
console.log("Login Error: ", data)
})
})
.catch((error) => {
console.error("Error:", error);
});

To access a private resource, the client app should include the « Authorization » header with the bearer
token (i.e. bearer JWT).

Example:

fetch("http://localhost:3004/users/" + props.user.id, {
method: "GET",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer " + props.token
}
})
.then((response) => {

if (response.ok) {
return response.json().then((data) => {
console.log("Get Profile - Your data is: ", data)
})
}

//else
return response.text().then((data) => {
console.log("Get Profile Error: ", data)
})
});
86
TP 8

1. Create a configuration file (routes.json) that protects the server resources as follows:
a. users: 600
b. messages: 640
c. products: 644

2. Configure the JSON Server auth to use “routes.json” and the port number 3004:
json-server-auth db.json --port 3004 -r routes.json

3. Update the Login/Register components as follows: After authentication/registration, the react


app receives the JWT and the User data.
a. check the received data after authentication/registration on the browser using DevTools

b. Save the received JWT and User object in the LocalStorage.

4. Create the Profile component that allows the user to see his profile. The endpoint that allows
the user with id=2 to read/update his profile is: http://localhost:3004/users/2
a. Is it possible to read the user profile without adding the JWT to the request header?

87
5. Create the EditProfile component that allows the user to edit his profile or password.

6. Use React Router to navigate between Profile and EditProfile


a. Add 2 routes to BrowserRouter: “/profile” displays the Profile component and
“/profile/edit” displays the EditProfile component
b. Add the “Profile” item to the dropdown list of the Navbar
c. If the user clicks on the “Edit” button of the Profile component, he will be redirected to
the EditProfile component (route: “/profile/edit”)
d. If the user updates correctly his profile or password from EditProfile, he will be
redirected to the Profile component (route: “/profile”)
e. If the user clicks on the “Close” button of EditProfile, he will be redirected to the Profile
component (route: “/profile”)

//Useful code to implement the navigation between Profile and EditProfile


export function Profile() {

return (
<>
<h2>Profile</h2>
<Link className="btn btn-primary" to="/profile/edit"
role="button">Edit</Link>
</>
)
}

88
export function EditProfile() {
const navigate = useNavigate();

function saveProfile() {
// read new profile data and submit an update request
navigate("/profile")
}

return (
<>
<h2>Edit Profile</h2>
<button className="btn btn-primary me-3"
onClick={() => saveProfile()}>Submit</button>
<Link className="btn btn-secondary" to="/profile"
role="button">Close</Link>
</>
)
}

7. Create the Users component that allows the admin to see the list of registered users.
a. Is it possible to allow the admin to read all the users on the server using the previous
“routes.json” configuration file?
b. Update the permission value of the users resource in “routes.json” and use users: 640.
Restart the JSON Server auth.
c. Add “role=admin” to the admin user in db.json file
d. Update the Navbar of the react app: if the user is admin, display the item “users” in the
dropdown list. This item displays the Users component which displays the list of users on
the server

89
6. Protected Routes
Link: https://www.robinwieruch.de/react-router-private-routes/

Protect the Profile component: check if the user is authenticated inside the protected component itself

function App() {
const [token, setToken] = useState(localStorage.getItem("jwt"));
const [user, setUser] = useState(JSON.parse(localStorage.getItem("user")));

return (
<BrowserRouter>
<Navbar />
<Routes>
...
<Route path="/profile" element={<Profile token={token} user={user} />} />
...
</Routes>
</BrowserRouter>
);
}

function Profile(props) {
if (!props.token) {
return <Navigate to="/login" />
}

return (
<h2>Profile (Protected: authenticated user required)</h2>
)
}

We protected the Profile component with React Router.

 However, this approach does not scale, because we would have to implement the same logic
in every protected route.
 In addition, the redirect logic should not reside in the Home component itself but as a best
practice protect it from the outside instead.

Therefore, we will extract the logic into a standalone component (let’s call it ProtectedRoute):

function ProtectedRoute (props) {


if (!props.token) {
return <Navigate to="/auth/login" />;
}

return props.children;
}

90
Then we can use ProtectedRoute as wrapper for the Profile component.

function App() {
...
return (
<BrowserRouter>
<Navbar />
<Routes>
...
<Route path="/profile" element={
<ProtectedRoute token={token} >
<Profile user={user} />
</ProtectedRoute>
} />
...
</Routes>
</BrowserRouter>
);
}

function Profile(props) {
return (
<h2>Profile (Protected: authenticated user required)</h2>
)
}

Let’s reuse this component for other routes which need the same level of protection. For example, the
Dashboard page requires a user to be logged in too:

function App() {
...
return (
<BrowserRouter>
<Navbar />
<Routes>
...
<Route path="/profile" element={
<ProtectedRoute token={token} >
<Profile user={user} />
</ProtectedRoute>
} />
<Route path="/dashboard" element={
<ProtectedRoute token={token} >
<Dashboard user={user} />
</ProtectedRoute>
} />

...
</Routes>
</BrowserRouter>
);
}

A better way of protecting both sibling routes with the same authorization level would be using a Layout
Route which renders the ProtectedRoute component for both nested routes:

91
function ProtectedRoute (props) {
if (!props.token) {
return <Navigate to="/auth/login" />;
}

return <Outlet />;


}

function App() {
...

return (
<BrowserRouter>
<Navbar />

<Routes>
...
<Route path="/products" element={<Products />} />
<Route element={<ProtectedRoute token={token} />}>
<Route path="profile" element={<Profile user={user} />} />
<Route path="dashboard" element={<Dashboard user={user} />} />
</Route>
<Route path="/contact" element={<Contact />} />
...
</Routes>
</BrowserRouter>
);
}

92
Chapter 5: JavaScript Syntax

I. Objects
Link: https://www.w3schools.com/js/js_objects.asp

Objects are variables. But objects can contain many values.

The values are written as name:value pairs (name and value separated by a colon).

Object Definition

You can create an object using an object literal. An object literal is a comma-delimited list of zero or
more pairs of property names and associated values of an object, enclosed in curly braces ({})

This code assigns many values (Fiat, 500, white) to a variable named car:

const car = {type:"Fiat", model:"500", color:"white"};

Spaces and line breaks are not important. An object definition can span multiple lines:

const person = {
firstName: "John",
lastName: "Doe",
age: 50,
eyeColor: "blue"
};

Object Properties

The name:values pairs in JavaScript objects are called properties:

Property Property Value


firstName John
lastName Doe
age 50
eyeColor blue

93
Accessing Object Properties

You can access object properties in two ways:

objectName.propertyName

or

objectName["propertyName"]

Example:

let name = person.lastName;


name = person["lastName"];

Object Methods

Objects can also have methods. Methods are actions that can be performed on objects. Methods are
stored in properties as function definitions.

const person = {
firstName: "John",
lastName : "Doe",
id : 5566,
fullName : function() {
return this.firstName + " " + this.lastName;
}
};

In a function definition, this refers to the "owner" of the function.

In the example above, this is the person object that "owns" the fullName function.

- this.firstName means the firstName property of this.

Object literal syntax vs. JSON

The object literal syntax is not the same as the JavaScript Object Notation (JSON). Although they look
similar, there are differences between them:

- JSON only permits property definition using the "property": value syntax. The property name
must be double-quoted
- JSON object property values can only be strings, numbers, true, false, null, arrays, or another
JSON object. This means JSON cannot express methods or non-plain objects like Date or RegExp.

JSON is a strict subset of the object literal syntax, meaning that every valid JSON text can be parsed
as an object literal, and would likely not cause syntax errors.

94
II. Arrays
1. Description

An array enables storing a collection of multiple items under a single variable name, and has members
for performing common array operations.

Syntax:

const array_name = [item1, item2, ...];

Example:

const cars = ["Saab", "Volvo", "BMW"];

You can also create an array, and then provide the elements:

const cars = [];


cars[0]= "Saab";
cars[1]= "Volvo";
cars[2]= "BMW";

Accessing Array Elements

const cars = ["Saab", "Volvo", "BMW"];


let car = cars[0];

Changing an Array Element

cars[0] = "Opel";

2. Array Methods

The following table lists the methods that mutate the original array, and the corresponding non-
mutating alternative:

Mutating methods Non-mutating methods : returns a new array


adding push, unshift concat, [...arr] spread operator
removing pop, shift, splice filter, slice
replacing splice, arr[i] = ... assignment map
sorting reverse, sort copy the array first, toReversed, toSorted

95
Add items

- push
- unshift
- concat: used to merge two or more arrays. This method does not change the existing arrays, but
instead returns a new array.

const array1 = ['a', 'b', 'c'];


const array2 = ['d', 'e', 'f'];
const array3 = array1.concat(array2);

console.log(array3);
// Expected output: Array ["a", "b", "c", "d", "e", "f"]

- 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.

const numbersOne = [1, 2, 3];


const numbersTwo = [4, 5, 6];
const numbersCombined = [...numbersOne, ...numbersTwo];

Remove items

- pop
- shift
- splice
- filter: creates a shallow copy (A shallow copy of an object is a copy whose properties share the
same references as those of the source object from which the copy was made) of a portion of a
given array, filtered down to just the elements from the given array that pass the test
implemented by the provided function.

const words = ['spray', 'limit', 'elite', 'exuberant', 'destruction', 'present'];


const result = words.filter(word => word.length > 6);

console.log(result);
// Expected output: Array ["exuberant", "destruction", "present"]

- slice: returns a shallow copy of a portion of an array into a new array object selected from start
to end (end not included) where start and end represent the index of items in that array. The
original array will not be modified.

const animals = ['ant', 'bison', 'camel', 'duck', 'elephant'];

console.log(animals.slice(2));
// Expected output: Array ["camel", "duck", "elephant"]

console.log(animals.slice(2, 4));
// Expected output: Array ["camel", "duck"]

console.log(animals.slice(1, 5));
// Expected output: Array ["bison", "camel", "duck", "elephant"]

96
console.log(animals.slice(-2));
// Expected output: Array ["duck", "elephant"]

console.log(animals.slice(2, -1));
// Expected output: Array ["camel", "duck"]

console.log(animals.slice());
// Expected output: Array ["ant", "bison", "camel", "duck", "elephant"]

Replace items

- splice
- arr[i]
- map: creates a new array populated with the results of calling a provided function on every
element in the calling array.

const array1 = [1, 4, 9, 16];

// Pass a function to map


const map1 = array1.map(x => x * 2);

console.log(map1);
// Expected output: Array [2, 8, 18, 32]

Sort items

- reverse: reverses an array in place and returns the reference to the same array, the first array
element now becoming the last, and the last array element becoming the first.

const animals = ['ant', 'bison', 'camel', 'duck', 'elephant'];


const nextList = [...animals];
nextList.reverse();
// Expected output: Array ["elephant", "duck", "camel", "bison", "ant"]

- sort
- toReversed: this is the copying counterpart of the reverse() method. It returns a new array with
the elements in reversed order.

const items = [1, 2, 3];


const reversedItems = items.toReversed();

console.log(reversedItems); // [3, 2, 1]
console.log(items); // [1, 2, 3]

- toSorted: this is the copying version of the sort() method. It returns a new array with the
elements sorted in ascending order.

const months = ["Mar", "Jan", "Feb", "Dec"];


const sortedMonths = months.toSorted();

console.log(sortedMonths); // ['Dec', 'Feb', 'Jan', 'Mar']


console.log(months); // ['Mar', 'Jan', 'Feb', 'Dec']

97
III. JavaScript ES6
https://www.w3schools.com/js/js_es6.asp

IV. Update Objects in React State


https://react.dev/learn/updating-objects-in-state

V. Update Arrays in React State


https://react.dev/learn/updating-arrays-in-state

98

You might also like