Understanding React Simplest Practical (001 036)
Understanding React Simplest Practical (001 036)
React
The Simplest Practical Guide
to Start Coding in React
Includes:
React Hooks and React Router
+ Full Stack Authentication
& Authorization Flow
While the author have used good faith efforts to ensure that the information
and instructions contained in this work are accurate, the author disclaim all
responsibility for errors or omissions, including without limitation responsibility
for damages resulting from the use of or reliance on this work. Use of the
information and instructions contained in this work is at your own risk. If any
code samples or other technology this work contains or describes is subject
to open source licenses or the intellectual property rights of others, it is your
responsibility to ensure that your use thereof complies with such licenses
and/or rights.
Contents
Development Environment 7
I Introduction 8
1 Essential JavaScript Concepts 9
1.1 Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
1.2 Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
1.3 Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
1.4 Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
1.4.1 A Prototype-Base Language . . . . . . . . . . . . . . . 19
1.5 Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
1.6 The Multiple Meanings of this . . . . . . . . . . . . . . . . . . 24
1.7 Modules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
1.8 Single Thread Language . . . . . . . . . . . . . . . . . . . . . 30
1.9 The Promise Object and the async/await Keywords . . . . . . 32
II Understanding React 37
2 Essential React Concepts 38
2.1 React Principles . . . . . . . . . . . . . . . . . . . . . . . . . . 38
2.2 Creating a React Project . . . . . . . . . . . . . . . . . . . . . 39
2.3 React Components . . . . . . . . . . . . . . . . . . . . . . . . 40
2.4 Rendering Components . . . . . . . . . . . . . . . . . . . . . . 41
2.4.1 Styling . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
2.5 Props . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
2.6 State . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
3
CONTENTS 4
5
What is this book about?
6
Development Environment
There are many development environments out there, and you can choose
the one you are more comfortable with. In any case if you don’t have
a preference, I recommend Visual Studio Code (VS Code). And to be
more productive, especially if you are new to React, I suggest installing
the extension VS Code ES7 React/Redux/React-Native/JS snippets which
provides JavaScript and React snippets. I would also suggest installing
Prettier, which is a JavaScript/React code formatter.
To install an extension, in Visual Studio Code, go to the File menu, then
Preferences and then Extensions. You will see a search box that will allow
you to find the extensions that you want to install.
Finally, I really recommend configuring VS Code to format your source
files on save. You can do that by going to the File menu, then Preferences
and then Settings. On the search box type Editor: Format On Save. This
will format your code right after you save it.
7
Part I
Introduction
8
Chapter 1
You can use React just by learning from React docs and you will also be able
to build applications, without digging into JavaScript. However, if you want
to master React and that means, understand why and how certain things
work, you must learn some specific concepts from JavaScript.
In this chapter we will explain those JavaScript concepts and syntactical
constructions needed to make a solid learning path to React. If you want
to dig in more details on some of the topics explained here or others about
JavaScript I recommend to visit the Mozilla[1] web site. Indeed, this section
is based on learning paths and ideas taken from there. Having said that, let’s
begin.
From the Developer Mozilla JavaScript Documentation [1] JavaScript is
defined as:
“JavaScript (JS) is a lightweight, interpreted, or just-in-time compiled
programming language with first-class functions. While it is most well-known
as the scripting language for Web pages, many non-browser environments also
use it, such as Node.js, Apache CouchDB and Adobe Acrobat. JavaScript
is a prototype-based, multi-paradigm, single-threaded, dynamic language,
supporting object-oriented, imperative, and declarative styles.”
9
CHAPTER 1. ESSENTIAL JAVASCRIPT CONCEPTS 10
Let’s then begin learning. Any piece of code written in this chapter will
run using the node interpreter. Install the latest LTS version of Node.js.
Once installed, you can verify that it is working by open a console and type:
$ node -v
That will display the version installed. With this in place, you can execute
a JavaScript file in the following way:
$ node yourjsfile.js
Using Visual Studio Code, you can go to the menu "Terminal" and then
"New Terminal". It will open a small terminal window where you can run
your scripts.
Printing text on the screen must be the very first thing you learn every
time you start playing with a new programming language. This book is not
the exception. You can print text on the screen using the Console object
like the following example:
1 console.log("Coding in React!");
Let’s then open VS Code to try this out. Open a console from your
operating system, create a new folder called ’chapter1’, and then type: code
chapter1. That will open VS Code ready to be used inside of the ’chapter1’
folder. Create a new file called console.js, copy and paste the previous
snippet in that file, save it and execute it typing:
$ node console.js
The object Console was created mainly for debugging purposes, it should
not be used in production. It gives you access to the Browser’s debug console.
It is also not part of the standard, but most modern browsers and nodejs
supports it.
CHAPTER 1. ESSENTIAL JAVASCRIPT CONCEPTS 11
1.1 Variables
Let’s move to variables. You can declare a variable using the let keyword:
1 let myFirstVariable;
Now if you print it you will see the string. You can also declare a variable
using the const keyword:
As you might have guessed, declaring a variable with const will not allow
you to change the value of the variable once it has been initialised. If you do
it the interpreter will throw an error. Try it!.
1.2 Functions
Let’s move now to functions. In the following code snippet we are declaring
a function and after that we are calling it:
1 function saySomething(string) {
2 console.log(string);
3 }
4
5 saySomething("Hello Function!");
CHAPTER 1. ESSENTIAL JAVASCRIPT CONCEPTS 12
If you just need to have a function that gets called as soon as it is declared,
you can use the syntax below. This is called IIFE (Immediately-invoked
Function Expression).
1 (function saySomething(string) {
2 console.log(string);
3 })("Hello Function!");
1 function returnSomething(string) {
2 return "This is it: " + string;
3 }
4
Both say and returnSomething points to the same place which is the
first statement in the body of the function. In the next example, on line
12 we are invoking a function and passing the returnSomething function as
argument. Note how then is invoked on line 8 and its return value returned.
1 function returnSomething(string) {
2 return "This is it: " + string;
CHAPTER 1. ESSENTIAL JAVASCRIPT CONCEPTS 13
3 }
4
1.3 Arrays
Arrays are another very important construction that we will use massively.
This is how you can declare an array:
CHAPTER 1. ESSENTIAL JAVASCRIPT CONCEPTS 14
4 //an array
5 let family = ["Jóse", "Nicolas", "Lucia", "Enrique"];
The elements of an array can be accessed by its index, where the index
of the first element is 0.
1 //an array
2 let family = ["Jóse", "Nicolas", "Lucia", "Enrique"];
3 family[0]; //Jóse
4 family[1]; //Nicolas
5 family[2]; //Lucia
6 family[3]; //Enrique
And if you want to add the elements of an existing array to another array
(empty or not), you can use what is known as spread syntax :
To simply iterate over an array you can use the following for construction:
And in addition we have a set of very useful methods. Let’s see first how
we can iterate over an array using the .forEach method:
3 family.forEach((value) => {
4 //do something with the value here
5 });
Note that we are passing an arrow function to the .filter method with
a condition testing the length of each element in the family array. Those
elements whose length is greater than 5 will be part of the returned new
array. Also note that the family array is not changed at all.
The last method we will see is .map. This method receives a function,
same as the previous two methods, and it will return a new array with the
result of applying the function to every element. It will always return an
array of the same length as the one we are processing. As we will see later,
.map is very used in React to add markup to the elements of arrays.
If you have an array with few elements, instead of working with indexes,
there is a very convenient way called destructuring that allows you to assign
each element of the array to named variables. See below:
1.4 Objects
There are several ways to create objects in JavaScript. We will study those
that will be used further in the book when coding in React. The first way
to create objects that we will see is called Object Literal. An object literal
is created wrapping within curly braces a collection of comma-separated
property:value pairs.
As you can see an object literal can be composed not only of simple
property-value pairs but also for arrays, other objects like address and functions
(called methods). Additionally, since ES6, you can create object literals with
what is called computed property names, like shown below on line 6:
5 surname: "Molinari",
6 [aproperty]: "+54 2920 259031"
7 };
1 console.log(mi.name); //Enrique
2 console.log(mi.sports[0]);//football
3 console.log(mi.address.street);//San Martin
4 console.log(mi.phone);//+54 2920 259031
5 mi.allSports(); //invoke the function and prints the sports array
1 let obj1 = {
2 a: 1,
3 b: 2,
4 };
5 let obj2 = {
6 c: 3,
7 d: 4,
8 };
9 let obj3 = { ...obj1, ...obj2 };
10 //obj3 = { a: 1, b: 2, c: 3, d: 4 }
And if you want to create an object from some declared variables, you
can do this:
1 let a = 1,
2 b = 2;
3 let obj4 = {
CHAPTER 1. ESSENTIAL JAVASCRIPT CONCEPTS 19
4 a,
5 b,
6 };
7 //obj4 = { a: 1, b: 2 }
So far we have seen object literal syntax and what you can do with it.
But what if you don’t know how many objects you will need to create? You
need something like a class from class-based languages like Java or C++.
In JavaScript, we have what is called constructor functions. As we will
see later, JavaScript has added classes to the language, but they are just a
syntactic sugar on top of functions.
A constructor function’s name by convention starts with a capital letter.
Lets see how to create and use them:
As you can see, the function Book looks like a class’s constructor of a
class-based language, in which, in addition, we are able to declare right there
methods like fullName(). We define properties and we initialise them with
the function parameters on lines 2, 3 and 4. On line 5 we define a method.
After that, on lines 10 and 14 we are creating two instances of two different
books and then invoke the fullName() method.
As you can see in the previous example code, the two instances of the Book
constructor function includes, in addition to the property names (and their
values), the function implementation code. Source code is not shared across
the instances like it is in class-based languages. This is an implementation
detail of the language which if you are not aware of it might lead to inefficient
programs. And what about inheritance which is a valuable language resource
used by developers? If there are no classes, do we have inheritance? Yes,
we have. The difference, among others, is that this relation is dynamic,
CHAPTER 1. ESSENTIAL JAVASCRIPT CONCEPTS 21
1 thisBook.fullName();
JavaScript will try first to find the fullName() method in the thisBook
instance. As it is not defined there, JavaScript will then look in their
prototype object and because it’s there it will be called.
Every prototype chain will end up pointing to Object.prototype. So, if
you execute the following:
1 thisBook.valueOf();
JavaScript will try to find the method valueOf() in the thisBook instance.
Then on their prototype and finally on the prototype object of their prototype,
which is Object.prototype. The method is there, so it is called.
Let’s now create a basic inheritance example. We are going to create a
new EBook constructor function that will inherit from Book.
7 //printing eBook:
8 //eBook: EBook {
9 // name: 'Understanding React',
10 // authors: [ 'Enrique Molinari' ],
11 // publishedYear: 2021,
12 // filesize: 2048
13 //}
CHAPTER 1. ESSENTIAL JAVASCRIPT CONCEPTS 23
1 Object.setPrototypeOf(eBook, Book.prototype);
2
1.5 Classes
Yes! JavaScript has classes and their syntax is pretty similar to most of the
class-based languages you might know. They were added to the language in
2015 as part of the EcmaScript 6. The thing is that classes in JavaScript are
a syntactic sugar on top of constructor functions and prototype inheritance.
Behind the scenes, everything works like a prototype-based language, even if
you define instances from classes. That is why it is important to understand
the previous sections.
We will implement our Book and EBook constructor functions with prototype
inheritance from the previous section but using classes.
1 class Book {
2 constructor(name, authors, publishedYear) {
3 this.name = name;
4 this.authors = authors;
5 this.publishedYear = publishedYear;
6 }
7
CHAPTER 1. ESSENTIAL JAVASCRIPT CONCEPTS 24
What we did in the above example with classes, the EBook and Book
inheritance relationship is the same as what we did with the EBook and
Book constructor functions in the section before. See the following code that
demonstrate this:
are some details you should know specially if you use classes for your React
components.
So far, if you use this in constructor functions and classes, and create
the instances using the new keyword, this is bound to the object being
instantiated. However, specifically with constructor functions this won’t work
as expected if you just call the function like in the next example:
1 function Constr(param) {
2 this.param = param;
3 }
4
Calling the constructor function as we are doing on line 5 will bind this
to the window global object. So, this example works perfectly, but what
it does is probably something you don’t expect. This example will end up
adding the param property to the window object and assigning to it the value
2.
On classes, on the other hand, if you need to assign or pass as an argument
a method, that method will lose the binding of this. Let’s study the next
example:
1 class Person {
2 constructor(name) {
3 this.name = name;
4 }
5 saySomething() {
6 console.log(this.name + " is talking...");
7 }
8 }
9 let enrique = new Person("Enrique");
10 enrique.saySomething(); //Enrique is talking...
11
1 class Person {
2 constructor(name) {
3 this.name = name;
4 this.saySomething = this.saySomething.bind(this);
5 }
6 saySomething() {
7 console.log(this.name + " is talking...");
8 }
9 }
10 let enrique = new Person("Enrique");
11 enrique.saySomething(); //Enrique is talking...
12
On line 4 above we are explicitly binding the value of this to the saySomething
method. Inside the constructor the value of this is the object being instantiated.
Now, when saySomething is invoked by the o() call, on line 14, it will work as
expected. Another way to fix this is by declaring methods as arrow functions.
1 class Person {
2 constructor(name) {
3 this.name = name;
4 }
5 saySomething = () => {
6 console.log(this.name + " is talking...");
7 }
8 }
9 let enrique = new Person("Enrique");
10 enrique.saySomething(); //Enrique is talking...
11
Defining the method using the arrow function syntax will work because
arrow functions retain the this value of the enclosing lexical scope which in
this case is the class. However, arrow functions in classes will not get added
to the prototype of the object being instantiated, which means, as we have
already discussed, that every instance will have its own copy of the method.
1.7 Modules
The 6th edition of ECMAScript in 2015 has also added the possibility of
defining modules. Before this release there were other options to create
modular JavaScript programs using tools like RequireJS, among many others.
Now we have this functionality supported natively by modern browsers.
Its use is pretty simple. You can define functions, classes, objects, constants
in a JavaScript file and export those that you want other modules to be used.
Additionally, the client module must import those abstractions that it wants
to use. Let’s see some code examples.
17 print() {
18 console.log("printing: ", this.name);
19 }
20 }
3 function complexThing() {
4 console.log("a complex thing has been executed...");
5 }
6
7 let obj = {
8 a: 1,
9 b: 2,
10 };
11
12 class ASimpleClass {
13 constructor(name) {
14 this.name = name;
15 }
16
17 print() {
18 console.log("printing: ", this.name);
19 }
20 }
21
Everything can be exported at the end just like we are doing on line
22 above. Of course, you don’t have to export everything from a module,
just those abstractions that represent the public API of your module. Let’s
see below how from a module called main-module.js you can import the
abstraction exported by the complex-module.js.
As you can see on line 3 we are importing the three abstractions that the
complex-module.js exports. We are able to use the abstractions imported as
if they were declared in the main-module.js file.
There is a common practice to define a default export abstraction from
a module in order that client modules can import those a bit easier. In the
code below, on line 22, we are exporting the class as our default exported
abstraction from the module.
3 function complexThing() {
4 console.log("a complex thing has been executed...");
5 }
6
7 let obj = {
8 a: 1,
9 b: 2,
10 };
11
12 class ASimpleClass {
13 constructor(name) {
14 this.name = name;
15 }
16
17 print() {
18 console.log("printing: ", this.name);
19 }
20 }
21
On line 3 below, note how we are importing the default exported abstraction
with a different name (it is an alternative, but we can use the same name).
Note also that there are no curly braces.
3 setTimeout(() => {
4 console.log("callback");
5 }, 1000);
6
7 console.log("finishing");
Below we can see the sequence of tasks to execute of the program above:
1. Statement on line 1 is pushed on to the call stack and executed. "starting"
is printed on the console.
CHAPTER 1. ESSENTIAL JAVASCRIPT CONCEPTS 31
4. After one second elapsed from the setTimeout function, the callback
arrow function passed as the first argument was then pushed into the
callback queue. Since there are no more statements to be executed on
the call stack, the event loop gets from the top of the callback queue
the arrow function and pushes it into the call stack. Finally it gets
executed. "callback" is printed on the console.
Note that all the callback functions that end up in the callback queue get
executed after the call stack is empty and not before (when the execution of
the program ends with the last statement). To be very clear with this, look
at the example below.
1 console.log("starting");
2
3 setTimeout(() => {
4 console.log("callback");
5 }, 0);
6
7 console.log("finishing");
1 console.log("starting");
2 fetch("https://jsonplaceholder.typicode.com/posts/1")
3 .then((response) => response.json())
4 .then((json) => console.log(json));
5 console.log("finishing");
fetch is delegated to the Web API which performs an ajax call. Once
the server respond, the callback arrow functions are pushed into the callback
CHAPTER 1. ESSENTIAL JAVASCRIPT CONCEPTS 32
queue. The first callback function, on line 3, transforms the response obtained
from the server to json and the next callback function on line 4 prints that
json in the console. Only after printing on the console the text "finishing"
on line 5, is when those callbacks functions are pushed into the call stack and
executed. You can find a more detailed explanation about the JavaScript
interpreter and how it works, in the great talk by Philip Roberts[5].
Suppose that now, something goes wrong with the executor and the
reject function is invoked. Then, it is possible to handle that in the following
way:
During this book, and usually in React we don’t write promises, but we
use them frequently. By using the fetch method to retrieve data from an
external API, we have to deal with a promise. Look at the example below:
1 function fetchPost() {
2 fetch("https://jsonplaceholder.typicode.com/posts/1")
3 .then((response) => response.json())
4 .then((json) => console.log(json));
5 }
6
7 fetchPost();
As you can see on line 2 above, the fetch method returns a promise,
which allows us to call the then method on it, to work with the response
CHAPTER 1. ESSENTIAL JAVASCRIPT CONCEPTS 34
data.
Another way to deal with promises is by using the async and await
keywords. These keywords were added to Javascript on ES2017 allowing
us to write asynchronous code in a synchronous way. Let’s rewrite one of
our previous examples to take advantage of these keywords. First, we will
create a function that returns a promise. Functions that return promises are
(usually) asynchronous:
1 function thePromise() {
2 return new Promise(function (resolve, reject) {
3 //long async operation
4 setTimeout(() => resolve("finished"), 1000);
5 });
6 }
8 testingKeywords();
First note that we have to wrap the calling code in a function. And
that function must be declared async (see line 1). Then, we use the await
keyword before calling the thePromise() function, on line 3. data (the right
hand side of the assignment on line 3) is actually the "finish" string, and
not the promise returned by thePromise() function. Why? because the
execution of the code inside the async function is paused until the promise
is resolved (or rejected). Messages inside the async function are printed on
the console in the same order as the order of the written statements. That
is why we can say that using these keywords allow us to write asynchronous
code that reads like synchronous.
Now we are going to rewrite the fetchPost() function to use these new
keywords. See below:
CHAPTER 1. ESSENTIAL JAVASCRIPT CONCEPTS 35
7 fetchPost();
As you can see, again, we are declaring the function async, and in this case
the fetch call on line 2, is prepended with the await keyword. Prepending
the await keyword to the fetch function means that instead of returning a
Promise object, it returns (if the promises resolve, you can use a try/catch
block to handle errors) a Response object. That allows us to call on line
3 directly to the json() method of the Response object. As that method
returns a Promise, we also prepend the sentence with the await keyword,
giving us a Javascript object that is finally printed on the console.
11 fetchPost();
And finally, async functions returns always a Promise. Suppose the
example below where we have an async function that returns the json response
from a fetch request. And with that, we would like to print it on the console.
If we do it like below (see line 6), we will get printed Promise { <pending> }
on the console.
1 async function fetchPost() {
2 let data = await
,→ fetch("https://jsonplaceholder.typicode.com/posts/1");
CHAPTER 1. ESSENTIAL JAVASCRIPT CONCEPTS 36
6 console.log(fetchPost());
1 fetchPost()
2 .then((data) => console.log(data));