0% found this document useful (0 votes)
16 views151 pages

Content

contenet

Uploaded by

suriyathaagam
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
16 views151 pages

Content

contenet

Uploaded by

suriyathaagam
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 151

hey everyone this is Anson today I'm going to teach you how to get started with

learning react if you're trying to


break into front development whether to get a job as a front developer or just as a
hobby then this is the right place
to be many of you will have different goals with learning react some of you want to
build a web application or you
want to build a mobile application or both perhaps you've heard about framework
such as nextjs and remix both
are react based and they provide lots of great tools out of the box for building
modern web applications or maybe you
just want to build a very simple and plain static website whatever the case is this
tutorial will serve as a
foundation as all of these goals mentioned will require this initial step of
learning react now just keep in mind
that we will be focusing on the web based application we won't be Focus focusing on
mobile applications but
learning react will enable you to learn react native which will allow you to build
mobile applications now let's
first understand what exactly is react well it's just a front-end JavaScript
library and whenever you hear frontend
it just really means what the user what the customer the person that is using your
product your application will see
what they will interact with anything that they can view okay so if you go on your
browser and you type in any website
in the address bar it will load up the document that is the front end with react
you use it to build components
which are just renderable bits that make up your user interface so for example you
might have a website that has a
navigation bar it has a sidebar that you can scroll through posts user activity
feeds whatever it is you might have a
main section that will display posts made by a user and you can see comments
and stuff like that that entire thing is the whole user interface but what makes
makes up that user interface are these
reusable components which you'll learn more about later on in this tutorial react
focuses on The View so in other
words what the user sees and what they interact with react is also an unopinionated
Library which just means
that there's no right or wrong way to do things when we talk about unopinionated
tools there's no limitation there's no
rule set that you need to follow to use the tool itself okay so you can use react
however you choose to now why
Why learn React?
learn react well first of all it's still in high demand for front-end Developer
jobs it's used by many companies
including Fortune 500s and startups you can use it to build any type of application
so whether that be a web
application which is what we're going to be focusing on or a mobile application
using a framework called react native or
if you want to build a desktop application you can use something like electron or
tari it's simple to learn
for absolute beginners with zero experience building Progressive web applications
now like many things in
Prerequisites
life there are going to be prerequisites in order to learn react okay so these are
Elementary things that every single
frontend developer will need to learn first before they learn any front-end library
or framework such as you know
react angular vue.js you get the point so the three important things that you
must learn is HTML CSS and client side JavaScript I'm sure many of you will
probably already have these prerequisites down but if you don't know these three
things I highly recommend
you pause this video and spend some time just learning HTML CSS and clients side
JavaScript now many of you will be asking about resources I would recommend
w3schools.com this is a free resource this is what I use when I first started
learning how to build basic website they
have a lot of different resources available on this website to learn anything you
want but what you want to
do is go to this website and just click on HTML and then you'll see a bunch of
different sections that you can go
through and you can start off with the basics the introduction of HTML how it
works what is the purpose of it what is HTML etc etc and then once you feel
comfortable with it click on CSS and then this will teach you how to style
your HTML document and then once you are comfortable with that you can then go into
JavaScript but specifically you
also want to make sure that not only you are trying to learn the actual programming
language of JavaScript you
also want to make sure you know JavaScript for the client side so you want to go to
this section JS HTML Dom
JS browser Dom and then JS web apis and you want to go through those because this
is actually what's going to teach
you how to manipulate the HTML document using JavaScript okay remember that
JavaScript can also run on the server side with no JS and on the server side there
are different programming
interfaces that you would encounter that are not existent on the browser
environment okay so there are
differences so that's why I specifically mentioned client side JavaScript now
before we get started with setting up
our react project I do want to mention a couple things that you'll need on your
computer in order to actually set up
your react project so first make sure you have node.js installed I currently have
uh version 20 on my computer but
you can just go to nj.org and then download the latest LTS version is what I would
recommend you need this because
we're going to be using a build tool called vat in order to generate the react
project and then we're going to be
using npm which stands for node package manager to install our dependencies that
are needed for our react project so make sure you have this node.js installed just
click on this and it'll download
the installation file for you and it'll walk you through the wizard and it's pretty
easy to install and in order to
verify that nodejs was properly installed you want to go to your PO shell your
windows Powershell command
prompt or Mac or Linux terminal and you want to type node and then hyphen V and
you want to make sure that it has the correct version that you just installed if
this works that means node.js is
working properly on your computer you also want to make sure that the command npm
is working as well so just type npm
Hy and V and this will show you the version of npm npm is automatically installed
when you install node.js so I
just wanted to mention that now for the text editor I'm going to be using visual
studio code it doesn't really matter what you use but I figured I'll would
just bring that up and in case some of you might not be familiar with Visual Studio
code you might be using something else but I would recommend using vs code
because it would just be a lot easier to follow along okay now we're going to go
ahead and get started with setting up
our react project so again like I said before we're going to be using vit which is
a frontend build tool that allows you
to scaffold front-end projects now we're specifically using it for react but you
could use it for other projects as well
such as vue.js if you've heard about that framework before so what we're going to
do is we're going to go into our windows power shell or your Linux or
Setup React with Vite
Mac OS terminal and we're going to type npm and now you see why we need no JS as
well as npm in our computer so we're going to type npm create V at latest and
this will run the prompt for us to create a v project so we're going to give our
project a name I'm going to
call this react hyphen tutorial and I'm going to use my arrow keys now to select
the framework so you want to make sure you select react going to hit enter and then
now you're going to select the
variant so we're going to go down and select JavaScript and then now we are done so
it created a folder for us in the documents folder and it named it based off of our
project name so react
tutorial so now we just have to CD into the react tutorial folder so CD react
hyphen tutorial and there are two more steps that we need to do we need to install
all of the dependencies and then
we're going to run the react project just so that we can see that it's working so
what I'm going to do is I'm
Install NPM Dependencies
going to type npm install and this will take a couple of
seconds depending on how fast your internet speed is because it is downloading
these modules from the node
package manager registry so that was pretty fast so uh you can see that it added a
bunch of packages and then now
we're going to go ahead and run uh the dev script we're going to type npm run Dev
so this is going to
start up our project and we're going to hit enter and now you can see that vit is
up
and running it took 394 milliseconds and then you can see that it is currently
running on Port 5173 so now you can just
click on this link or just go to your browser and type in Local Host colon 5173 so
I'm just going to go ahead and
click that all right so now you can see it's just a plain website nothing really
fancy just has some static assets these
Vector icons has some text has a button so nothing crazy now let's go into the
actual code let's go into our text editor so again I'm going to open up visual
studio code and I'm going to have
my project open up just like this now there are a lot of files in here and it might
seem overwhelming but I promise
Project File Overview
you a lot of these files you don't really need to worry about we'll go through each
one very very quickly so
for example we have our V.C config.js file you're probably not going to be working
too much with this as a beginner
you can leave this file alone but if you ever want to make configurations to your
your V build tool command you would do
that inside this object over here okay we have a read me file nothing crazy with
this we have our package.json file
so this is our manifest file it has information about the project itself and you
can see we have scripts set up over
here that Dev script that we ran earlier is right over here and you can see it's
just an alias for this V script and then
we have our dependencies listed so remember earlier when we ran npm install what
happens is it will look inside this
package.json file and it will install all of these dependencies listed over
here so it downloaded react and react Dom these are two separate packages and then
it also downloaded all of these Dev
dependencies or developer dependencies which help enhance the developer experience
when you're working on your
project and all of these packages are hosted on the npm registry and then it
downloads to this node modules folder right over here so all of those packages
all that code get it's downloaded and stored into this node modules folder in your
project we have our package lock.
Json file we're not going to worry about that I'll come back to the index.html file
in just a bit but I just wanted to
mention that we also have our get ignore file and we also have our eslint file
you're not going to really need to worry
about these things unless if you want to use eslint uh if you're a complete
beginner don't worry so much about it I
don't want to over overwhelm all of you so we have our source folder and right now
you see that there's a lot of stuff
inside The Source folder but you know what I'm going to do is I'm going to actually
delete all of these files
except for one file so let me go ahead and right click and delete everything in
here and I encourage you to do that as
well so that way you don't get overwhelmed with everything that's happening okay so
now we're going to go
into this main.js jsx file so remember delete all the files except for the
main. jsx file the reason why we're not going to delete this is because this is
our entry point to our application so this is the root file for our react
application so you can see over here that we have a couple of import statements in
fact I'm going to go ahead
and remove this import app from app.jsx because we just deleted that file so
that file no longer exists because you cannot import a file that doesn't exist
otherwise you're going to get an issue
we're going to also remove this index.css file because we no longer have that file
and then since we remove that
app import I'm going to also remove this app tag over here and this looks like
HTML and in fact just a sneak peek this is actually how you render components in
react but I'm going to go ahead and remove this as well okay great so now that we
have a lot less stuff to worry
about let's walk through what's going on in this main. jsx file and why this file
is important so the first two things is it's importing react from that react
module and it's also importing react Dom so this allows us to actually have these
methods called create root as well as render and what happens here is we need
to set up a root for our react Dom because remember react Dom allows us to
actually render these react components to a virtual Dom so doesn't actually
render it to the actual document itself it renders it to a virtual Dom which makes
a lot more
faster so what happens here is we call this create root method
and you can see as an argument to this method it uses this get element by ID
method that's part of the document API and it it it looks for an element by the
ID of roots now if you have went through the basics of client side JavaScript this
might be familiar with you if it
isn't that's okay all you need to know is that this is using the browser API to
search for an HTML element by the ID and
we're specifically looking for uh an ID of roots okay once it looks for that ID
of roots it's going to go ahead and call this render method and then this is where
we're
going to want to actually uh render our components earlier you saw that it had
this app tag right over here so it was actually rendering the app component which
we deleted so don't worry
in fact what I can do is I'll just leave this empty for now and I want to show
you what actually happens when we go into our browser okay so what I'll do
now is I'll go into my terminal and I'll run npm
runev and let's go ahead and refresh the page right now and you can see now we just
have a plain blank page that has
nothing because we deleted everything okay now if I were to actually just uh set up
a random div over here let's just
say hello world you'll see that that hello world text will appear in the document
and so will that div so if I
actually go to the browser tool so you can actually easily access these browser
tools by hitting control shift I uh or
if you just right click and then click inspect it'll open up this browser tool
over here I'm currently using brave but this works on really any browser and then
what you want to do is you want to
uh go to the elements section and you can look at the HTML over here and then you
can see
right over here we have our body tag and then we have uh some tags over here as
well okay so now pay attention to this div right over here let me zoom in a
little bit you'll see how it has this ID of roots okay and then it also has this
div this is the div that we just rendered to the Dom and it had our hello world
text okay so this div is what is
being looked for right over here okay this this ID root can really be anything
you want okay it can be main it can be root you can call literally anything you
want now I'll show you what happens if we wanted to uh search for a different
ID so let's say if I type main instead of roots right now it's going to go ahead
and give us an issue in the
console it's going to say Target container is not a Dom element and that's because
there is no element in
the document that has the ID of main now if for whatever reason you want to
change the ID I'll show you how to do that so we're going to go back to our
index.html file that we skipped over and
you can see that there's a bunch of plain HTML that you should be familiar with
okay we have all of our basic HTML
tags we have our title tag in the head tag very simple stuff we have our body
tag that I want to focus on and you can see right over here we have our div tag and
notice how this div has that ID of
roots okay so earlier when we had this argument as root it was basically
looking for this div right over here okay well let's go ahead and change this to
Main and which means that we're going
to have to have an element that has an ID of main so I'm going to change that
to Main and now you'll see that the error actually goes away because that
document. getet element byid call can actually look for an element that has the ID
main okay so
you again this can be literally anything you want you just need to make sure that
you have that changed over here as well
okay the second thing that I want to mention is this script tag over here so
what happens is this so let's say for example if I were to just comment out this
script tag you'll notice that
nothing appears on the document in fact if you look at the uh the the browser or
the the source code over here you'll see that the only thing that is being rendered
to our uh browser is this div
right over here and you can see the common is right over here okay we don't
have our hello world being rendered out Okay the reason why that's happening is
because we need this script tag so what happens here is it loads up this entry
file this main. jsx file okay and these methods that are being called actually
does something called client side rendering so it loads up this script
file and then it's going to go ahead and you can kind of think of it as like
unpacking everything it's going to go
ahead and uh client side render all of your react code or all of your
JavaScript that you wrote in your react components and it's going to generate those
components into actual HTML
elements okay I'm not really going to go super in depth into that whole process but
I just wanted to mention that this
entry point file is very important without it you can see that your entire react
application is not going to appear
in the document okay so hopefully this whole process makes sense I wanted to go
in depth on this because I think understanding this is very important because it
also helps uh debugging and
diagnosing issues a lot more easier so in the next section of this tutorial I'm
going to show you how to get started
with setting up your first react component it's going to be a lot of fun so I'll
see you all in that section
Intro to Components
in this part of our react tutorial I'm going to teach you how to create a component
and render it to the document
before we do that I want to show you some diagrams to help you better visualize
components whenever you look
at a website I'm sure many of you are just used to looking at a website as a whole
but not ever thinking about the
individual pieces of the website in the form of a component that eventually Build
Together the final View
so let's look at this first diagram that I have over here we have a navbar
component which is responsible for
displaying links so you can click on it and go to a different page on the
application you have a posts component and it's responsibility is to display
posts made by either yourself or a user imagine this is some kind of social media
app okay you have a feed component
or an activity feed component and this can display events that are happening such
as when someone adds you as a
friend when someone followed you or whenever your favorite artist made a post to
their uh to their social media
page it'll display all over here and then you may have a footer component that
displays additional links or
miscellaneous details if we wanted to narrow this down and be more specific
keep in mind that a component can also render other components inside of it as well
and that is known as child
components okay in this next diagram you can see that I have this post group
component now this this diagram is actually just a more detailed view of
the previous diagram so the post group component is really just the same component
as the post component they
have the same responsibility of rendering posts okay now when we say
render posts what we really mean is that we are rendering um multiple instances of
a
post itself so we're going to call that component something like post item as an
example right and each post item is
going to have the same Fields the same properties right for example each post
item is going to have the title of the post the author of the post the date that
the post was created the amount of
reactions the post has etc etc okay but each post or each post item
their fields will have different values right because remember each post will have
different authors different
reactions different creation dates you get the idea okay a better way to think
of it especially if you've learned about object-oriented programming before think
of it like this you have post item as a
component and that component is a blueprint it describes how you are going
to display or render information to the page okay it's a
blueprint but keep in mind that a blueprint doesn't mean that every single uh final
creation of that blueprint or
every single uh derived creation of that blueprint is going to be the exact same
thing right you'll have a blueprint of a
house and while the house follows that blueprint the house can have different
uh you know countertops it can have different floorings like some houses may have
carpeting some houses may have
tiles some houses may have uh hardwood I think you get the idea different houses
can have different number of bathrooms it still is the same floor plan this it's
following the same blueprint it
just has different options and in this example we have the same post item instance
it's just each post item has
different information pertaining to its field again different author different
number of reactions different different
uh content okay you get the idea the same thing applies to our feed component again
you
have an activity feed that is the parent component because it renders feed item
so it's the parent component of these feed item components feed item component
is its own individual Blueprints and each feed item is going to be different
okay so I hope that this makes sense because it's going to really help you
understand how to render components and
how to design components effectively one more example I want to show you is this
mockup that I found on
dribbble.com and you can see that this is a website that could potentially be a
real e-commerce website and you can see we have our navigation bar we have our
links we have
this uh part over here and again as a regular user you might think of this as just
a plain image but you can think of
this as a promotional Banner component because its responsibility is to display
a promotional Banner for the user to tell them hey this item is currently on sale
buy it now and you can see that it has an image it has promotional text and it has
a call to action button if you
scroll down over here this is a better example that fits the uh post group and
feed example that I just mentioned okay so right over here you have these
individual elements that Are all uh
products right you have headphones being displayed but you can think of these
individual uh products as product item
components okay and notice how they all have the same format they have an image
they have this heart button this is known as a floating action button and this is
common on e-commerce websites
you can click on this button and it typically will save the item so you can view it
later uh you have the title the name of
the product a descrip deson the price and then the number of reviews um you have
the add to card
button so these product items follow the same structure it follows the same
blueprint but each one of them looks different okay they all have the same
templates but each instance of this product item component is going to
result into something different they have different images different text different
number of reviews you get the
idea and then all these product items are all wrapped inside a parent
component which typically we call a wrapper or a container component and it's
better to show you that in the form
of an example which you'll see when we actually get to rendering elements rendering
arrays which is known as
Dynamic rendering so hopefully this example made sense now let's go ahead and jump
into the
code so one important thing to understand is that one component comp
are Universal to literally any library or framework on the front end that you'll
use so if later on you choose to
use VJs or angular well the concept of components is ingrained in your head you
don't need to worry about that anymore
because it's the same thing in angular and in vuejs and any other framework you
just have to learn the syntax and another thing that you need to understand is that
with all these
Frameworks all these libraries you will always have one root component that
hosts the entire structure of the application so in other words we're going to need
to have one root one
parent component that will hold all of the other components also known as child
components so if you remember earlier we had a component called app that was
being rendered we actually deleted it and the reason why we deleted it was because
there was just a lot of content in that file and I didn't want to
overwhelm you all so what we're going to do is I'm going to remove this div hello
world and you can actually think of it
like this this div right over here is in fact our own component it just renders the
text hello world okay and the hello
world text is actually its own child component but I'm going to go ahead and remove
this and we're going to go ahead
Creating a Component
and create a new file we're going to recreate that Roots app component so I'm going
to call it
app.jsx and every single component is basically just going to be a function
Okay so in order for us to create a component we need a function so I'm going to
call it function app just like
this and then we also need to make sure we are exporting this function because
we want to import it anywhere that we want to render this component in our
situation we're only going to render it
once inside our main. jsx file or the entry point of our
application so what I'm going to do is I'm going to export this as a default export
just like this
now with components yes it's a function but this function needs to return
something and that something is known as jsx which I mentioned in the
introduction of this tutorial but jsx stands for JavaScript XML and I did
mention that it does look a lot like HTML and a lot of people mistakenly call
HTML because it's so similar but it is
jsx okay okay semantically yes there are differences and we're going to call it jsx
throughout the entire video so we're
going to use the return keyword and we're going to return some jsx so what does
that look like well HTML actually
is in fact valid jsx so for example if I want to use this div and then I want to
go ahead and return let's say an H1 tag that says Roots component just like that
this is valid jsx although it is also HTML this is also valid jsx so let's
keep it simple what we're going to do now is go back to our entry point file our
main. jsx file and I'm going to go
ahead and import up top over here on line three I'm going to import that app
component that I just created from the
app file and vs code allows me to autoc complete this but I can just do this
import app from app just like that so remember because this is a default
export I need to make sure I'm importing it as a default import as well okay so
just like this so no curly braces in this situation now what I'm going to do is in
between this react. strict
mode in between these Tags I'm going to go ahead and render the app component
just like this it's going to look exactly like how we would how we would render an
HTML element to the document
so angle brackets app and I could do it like this this is the long way to actually
render
components and react you would only do this if you actually were going to pass a
child component into the component
right over here into app but we don't have a child component that we're going to
pass into app at least we we're not going to do that right now for this
component so what we're going to do instead of using the long syntax is we're going
to shorten it by doing this
so angle bracket app and then closing it like this okay so now what I'm going to do
is I'm
going to go ahead into my browser and you'll see now it renders this H1 tag
into the document and if I open up the browser tools by just hitting control shift
I or just right click and then
just click on inspect or view page Source actually not view page Source
sorry just click on inspect and then you'll see that right over here in the body
tag right over here I see
my root div with the idea of main because we changed it earlier you know let me
actually change that back before
I forget let me change this back over here to roots and then go over to index.
HTML and change this to Roots just to be consistent but again if I expand you'll
see that I have this div and this div is right over here this is the root div
of my app component and this div holds my H1 tag that says Roots component
right over here so there you go that is your very first component in react now
obviously we're going to see a bunch of
other examples but this is our root component the app component is our root
component so I'll go ahead and show you some more examples with components I'll
actually create a new folder called
components and I'll place all of my component files in this components folder so
what I'm going to do is now
I'll create a new file and think about the component that you want to create you
don't have to copy the exact component that I'm going to create you
can be creative and try doing it on your own as well but think of any component you
want to create so I want to create a
component that represents a user profile so I'm going to call this component user
profile and I'm going to use Pascal
casing so the first letter of each word is going to be Capital so or capitalized
so user the letter U is going to be capitalized and F the letter P is going to be
capitalized and then end it with
jsx so now what I'm going to do is I'm going to go ahead and create my user profile
component so remember every
single component needs to one be a function and two return jsx I'm going to
keep repeating this throughout the entire part of this tutorial so that way it is
ingrained in all of your heads so
we need a function so we'll use the function keyword and typically you want
to name your function based off of the component and in my situation I'm going
to actually name it off of the file name so they all match and this is common
convention so user profile is going to
be the name of this function which is also going to be the name of my file and the
name of my
component and then remember that we also need to return jsx so return and uh you
can use a div you can also not just only use a div but you can use literally any
HTML tag you want you can use a section if you want to you can literally even use
navbar or not Navar nav if you want
to this is for navigation but let's stick to div for now and let's make sure we
export this
function so what I'm going to do is I'm actually going to export this as a named
export because sometimes you might want
to have other exports in this user profile file it doesn't just necessarily
have to be one single component that you might export we only did a default
export for app.jsx was because this is the root component and there's going to be
no other components inside of here but you can do this as a default export if you
really want to but I'm just going to
leave as a named export just to show you different patterns in different use cases
so again we have our div this is
going to hold all of our content for our user profile and I'm just going to go
ahead and use literally any HTML element that I want so I can use a paragraph tag
and I'll just uh do username Bob and let's see let's do
another div and let's do span tag let's do email and I'll use another span tag and
then we'll do anen anen the.com just showing you some simple examples right
um and let's see what else can we do I can do something like I can use a section
I could even use an unordered list and let's just do something like this let's
[Music] do uh let's see favorite
food and then let's do a break and let's do sushi and I'll duplicate this a
couple more times we'll do pizza and uh
mediteranian food hopefully I spelled that right okay now that we've cre our
component and return jsx and remember this is all HTML but we're going to call
it jsx we're going to go ahead and now render our user profile component inside
the app component because remember your app component is the root component
everything is going to belong to this
app component okay when we get into routing and and uh navigating users or
navigating ourselves between different parts of the application you're going to see
that it's actually going going to uh
be inside the root application itself so let's go
into uh inside this div so right underneath on line five I'm going to go ahead and
first let me import my
component so import and I'm going to use curly braces because I'm importing this as
a named import so user profile and
this is going to come from the components folder and then the user profile
file and then we're going to use angle brackets to
render our user profile just like this and now if I go into the Dom or the
browser you'll see that my component is being rendered and if I look at the dev
tools I can see that this is the div you know what let me actually go into user
profile let me give this div an ID so
that way we can easily detect it in the browser tools so you'll see that right now
over here this div is in fact uh the
user profile component and then we have all of the other HTML right over here
okay so really what actually happens is we are uh writing jsx we're writing our
code inside our jsx file and then when we actually render our component uh
react takes care of uh generating all of this from jsx into actual real HTML and
renders it into the actual virtual Dom itself okay and this is again known as
client side rendering so hopefully all of this makes
sense I do want to show you another way just to create components is not the
actual way that you're going to create components when you're writing your react
application but I did want to show
it to you regardless so I'm going to go ahead and create a new file and what I'll
do is I'll create a component
and I'll call this uh let's do user favorite foods and we're actually
going to uh show you two things at once so this is going to be a user
favorite foods component and what I'm going to do is I'm actually going to uh
abstract this part of the user profile so I'm going to take this section that had
this unordered list and I'm going to
move it into its own component and again this is something that you're going to do
often in react you're going to uh
take components and put them into other components so that way it makes it a lot
more easier for you to manage individual
createElement function
components so let's go ahead and do this I'm going to go ahead and import a
function from react and that function is going to be called create
elements and this is actually the old way of creating components in react we
don't actually do this anymore but underneath the hood react actually uses
these functions to create the actual elements that gets rendered to the virtual Dom
so I'm going to use this
create element function function and I'm going to give the name of the function
user favorite foods and then I'm going
to simply just first let me export this function and then I'm going to return
and then I'm going to not return jsx but I'm going to return the function call of
create element just like this now create element will take a couple arguments so
the first argument is going to be the
type so this is going to be the type of element the type of HTM element that you
want to actually create so we're going
to use div so we're going to do div you can use literally anything you want you can
use section you can use div whatever
you want and then the second argument is optional you can see that in the intell
sense it's telling you it's this second
argument is known as props we're not going to talk about props right now but will
get to that in just a bit we're
going to leave this as empty so you can either just pass in an empty object you can
do null you can do undefined
whatever doesn't really matter we'll just put an empty object for now or actually
no I'll do
no and then the third argument and any and every other argument afterwards
because this is actually all spread out because you can see over here that you can
actually pass in an indefinite
amount of uh arguments after the second argument so the Third third argument and
every other argument afterwards is going to be children of this div element that
you're creating so what that means is
right over here what I can do is I can literally just pass in any valid jsx so
for example if I wanted to pass in a div and say uh user favorite foods and if I
save this and now what I'm going to do is let me just before deleting the section
let me go ahead and render user
favorite foods so I'm going to import that inside my user profile and now you can
see how we are
building our hierarchy so I'm going to import that and then right down over here
I'm going to render user favorite
foods just like this okay and then if I go into my browser you're going to see user
favorite foods that text that is inside this div element and this div element is
inside this div element as well is being rendered if I go over here you see we have
this div which is this
div and then we have this inner div right over here which is the child of our
parent div hopefully that makes
sense I know that kind of sounds a little bit confusing but um let me do this now
what
I'll do is I'll take this entire section I'm going to copy it and I'm going to
just paste it literally right over here and now you're going to see if I
refresh uh you're going to see that
so inside the user profile component so this div right over here you can see
that I have this div which is this user favorite foods
component and then in that component it has this section as a child component or
a child element and it has our unordered list right over here okay so visually it
looks all the same but from codewise as a from the developer perspective it's
actually different okay but to the user itself they're not going to notice any
difference at all and one more thing
that I will do is actually I don't even need this div I can actually just change
this to section and I can
remove this section over here okay and now what we can do instead is we can
actually just put some commas uh right over here at the end of
the span at the end of the BR The Brak tag and then we don't need to do it for
these list items because it's all encapsulated in this unordered list but now if I
refresh and I want to show you
this because this is very important you're going to see that all of these elements
so this span this
break and this unordered list they are all part of the
section okay so literally every any any element you want to pass
in as an additional argument is just going to be an addition element that will be
appended to this section okay so
really what happens is it just adds the element to this section node right over
here okay as a child node so that's why when you hover over when you actually hover
over here it shows you that this
children argument over here is actually an array of react uh react nodes or react
elements and you can pass an
indefinite amount and they'll just all basically be appended to this uh section
element or whatever element it is right here hopefully that makes sense okay and
you'll notice that if I actually just
take this whole thing and if I put this in a div and if I remove the
commas all of these elements now will actually just go inside this div so
there'll be immediate child elements of the div but they will not be immediate
child elements of the section hopefully
that distinction makes sense okay but again um you're never going to really
use create element to actually create your uh components so you don't have to
worry so much about this if this is a little bit confusing uh just stick to
creating your components the first way
that I showed you just like this but I just figured I would show this to you all
just to kind of give you all a little history lesson because this is
what was how you would create components back then in very early early stages of
react okay and I'm talking about like 9 10 years ago when react first came out
but okay let's go ahead and move
Component Props
on so now what we're going to do is talk about component props in react so what
exactly are props or short for properties well props are pretty much
just data that you are passing in to your components and those components
take in those props they can take in that data and they can do literally whatever
they want with it they can use
that data and render it to the document they can take that data and send it to a
server by making an API call they can
take that data and pass it to another component um they can take that data and
concatenate it assuming it's a string or even a number they can concatenate it with
another piece of string or another
number they can do uh math operations such as adding that piece of data with
another numeric value whatever it is you can do literally anything you want with
props okay so what I'm going to
do is this I'm going to go ahead
and uh let me create a couple more components so I'll go ahead and create a new
file I'll call this
user username jsx and these are just going to be very simple components but
the idea is to show you how props work so export function user
username and this component's purpose is going to display the users
username okay so we're going to return a
div and what I'm going to do is I'm going to also make sure I prefix the username
with the actual with a label or
some text that indicates that this is the username so what I'm going to do is I'm
going to use a span
tag well actually not span I'm going to use the B tag which bolds this
text okay and what I want to do is I want to render the username in this span
tag right over here okay now here's the thing though how do I actually render
the username itself right well this is where we need to actually pass data to
this user username component so how do we do that
well what we're going to do is we're going to go into our user profile component so
where we are going to
render our user username component so I'm going to remove this P tag right over
here where I rendered this
hardcoded username Bob text and I'm going to render user username just like
that okay and to pass a prop to a component it's very easy all you do is
in between where these angle brackets are and right after where you have your
component name so after user username I'm going to go ahead and give
my prop a name now if you're using typescript which since we're not using
typescript you would need to
actually have type annotations for your components okay which makes it very
strict which is actually a good thing because that way you're not just randomly
passing in random props to
components that don't need that data but since we're using JavaScript I can
literally pass in any prop give it any
name I want but I'll show you also how to validate props later on using a package
called prop types so I'm going
to go ahead and give my prop name so I'm going to call it username you want to make
sure you're giving your props
relative names to the data that it is so for example if that data is username or
if it's email you want to make sure the prop corresponds to that piece of data so
username and we want to have an equal
sign and we're going to be passing a string down to this user username
component for this username prop so I'm going to use equal sign and I'm going to go
ahead and
give it the name Bob just like this and now we need to go to the actual
component that is going to be receiving this prop and in order for us to actually
be able to reference this
username prop the way that we handle that is well this user username remember
that this is a function and what's really happening is we're actually passing in
this username prop as an
argument to this fun function in other words when you actually render your
components and react you're actually
really just calling the function itself okay you're actually just calling this user
username function except you're
calling it by using these angle brackets tags okay when you pass in props you're
actually just passing in an argument to that function so all of those props you can
pass in as many props as you want
all of those props are all encapsulated into an object and that object gets
passed into to the component function and that argument is just called props
whoops props just like that let me show you what happens if I were to console log
props let's go into our browser and
you'll see how over here if I go to the console which you actually may have already
saw that already but if I go
over here to console if I refresh the page you'll see that uh we have username
Bob okay as a field or a key value here and it's in this object right over
here as an example let's say if I wanted to pass in some more props so let's just
pass in um let's just say uh trimmed
username just as an example you'll see now both username and
trimmed username are in this single props object right over here now if I
wanted to reference either one of these props username or Trimm username all I have
to do is just reference it by just
using the dot operator so Props Dot and then the name of the field and that's
always going to match the name of the
prop so username username just like this now you can see right over here it is
complaining because we have eslint
enabled it's complaining about it missing prop validation the code should
still work the applications should still run it's just that your uh vs code is
just giving this yes warning your your application will work fine though but if I
refresh you'll see now it is logging
just Bob because I am referencing props do username if I reference props do trimmed
username it's going to log Bob
as well so hopefully that makes sense now we want to actually render the username
to the document we're going to
do that inside this inside these span tags now in order to actually render the
username we know that it's coming from
that props do username field which is actually a field inside the object before we
rendered a username by
hardcoding it to the document but this time we actually have this value that is
defined in a field or you can kind of
think of it as like a variable right how do we actually render that how do we
actually extract that value from that
field end then render it to the document we're going to do something called
evaluation so for example if I reference props do username right over here this
is a literal value and in the document it'll just literally render prop. username
that's
Evaluating Props
not what we want we want to actually evaluate this object's field so that way
we actually get the value itself to do that we're going to actually wrap this in
between a pair of curly braces so
this will evaluate this props do username field and then it'll grab us that
username value so if you look at
the document right now you can see that Bob is being displayed to the document
because this username field was EV valuated I'm going to go ahead and remove this
console log now you can pass
in other data types as well you don't have to only pass in strings so just as an
example let's say let's remove
trimmed username uh let's do this so what don't want do this let's go into
our app component the root component and we'll pass in props to user profile so
let's pass in the age of the user so what I'll do is inside this div um I'm
going to go ahead and do this let me remove these two span tags let me remove this
div actually so I'll use uh a bold
tag and I'll do age and then span and then we're going to go ahead and expect
props so let me go ahead and pass that as a
argument for the user profile function and then we're going to go ahead and
reference
props and the name of the prop will be age so Props do Ag and then remember we're
evaluating that by using a pair of
curly braces so now let's go into our uh app.jsx file or really any file wherever
you are rendering the user profile component and then we want to pass in that
age prop so since we are passing in a numeric value we need to actually use a
pair of braces okay if I actually used quotation marks like I did earlier to
pass in a string it would pass in this numeric value as a string so if I put
20 it would treat age it would treat that age prop as a string instead of a
number and you'll see right over here if I actually rendered or not rendered
console log props and if I went to my
browser you'll see that it's treating the field as a string instead of a numeric
value which
is not what we want because you might want to do some kind of uh arithmetic and
you'll have to worry
about parsing it first so what we'll do is we'll use curly braces and then pass
in the number 20 just like this and now if I save and go back to the browser you'll
see now the number 20 doesn't
have quotation marks uh in between or around it so now this is an actual
numeric value so you don't have to worry about parsing it at all okay and then now
if you see right over here it is
rendering that prop it is rendering the age 20 just fine so that's
good and then you can also pass in uh booin if you wanted to so for example
let's say if I wanted to pass in uh let's say for user profile let's say we
want to pass a prop called is logged in and let's set this to True okay and then
then let's just evaluate the prop right now props is logged in now it's not
going to actually show you anything because this is a boene so it's not even going
to render the text at all but I
could just do something like this where I call a function or call the string
Constructor and then evaluate that so you'll see true is being rendered and I
can change this to false again just showing you this as an example later on you'll
learn about additional rendering
so you'll see how we can use a Bine to render specific stuff to the document
okay so uh that's just an example you can pass in arrays uh so let's just say
for example for user profile we have favorite foods and this might be an
array of favorite foods so this will be like an array of objects so let's just
say uh name Sushi okay and then what you would do is
you would reference the prop which you'll see right over here favorite foods whoops
let me go to the console
you'll see favorite foods is in fact an array and then what you would want to do is
something called Dynamic rendering uh
or in other words rendering lists so you would take that props dot favorite foods
array and then you would iterate through it and then you would render uh basically
each object as an actual
renderable element which this is something that I will show you later on okay
so uh yeah you can literally pass in anything you want you can pass in an object as
well you can pass in um you
can even pass in a function so let's say for example if I had uh call me so let's
create a random function uh let's do this let's not use
an alert let's just do console log hello and then let's just do uh
call me let's just pass as a prop you'll see
now the object props has this call me field which is a function and then you
can see that it has the implementation right over here but what I could do is I
could just immediately call props do call me like that and you'll see that
when I refresh the page uh it console logs hello which is pretty much calling
this call me function so hopefully that makes sense again you can pass in literally
anything you
Type Checking Props
want so now I'm going to show you how to use a third-party package called prop
types this is very important for type checking your component props because
you can see we are able to pass in any type of prop that we want without even
validating it at all and that's not good because you always want to make sure you
are validating what your component is
taking in as a prop and then you also want to make sure that those props are
actually being passed in if a component
expects one so what we'll do is we'll install this package so we're going to go
into
our terminal and type in npmi prop
types all right let me go ahead and run my app
again Perfect all right so now what we're going to do is anywhere that we have a
component so let's go into user profile okay we're going to go
ahead and import this package and I'm actually going to do this on the first line
so we're going to
import prop types like this from prop hyphen types just like that
okay once we import that we can go ahead and take our user profile function so
user profile Dot and then you can basically dynamically attach this
property prop types just like this to your function itself okay so user
profile. propop types and then inside this object over here you want to
basically Define the props that this component is expecting so for example
this component right over here expects uh currently only one prop but you know
what I'll do is I'll actually do this uh I'm going to take this username
prop uh let's do this let's go back to app I'm going to pass in a username to
user profile so let's just do Bob and we're going to this is known as prop
drilling by the way we're going to take the prop that we passed from the app
component to user profile we're going to take that prop and then pass it to user
username
component so Props do username just like this okay so I'm basically taking the
prop uh that was passed to user profile and then passing it down one more layer to
its child component user username and
you can definitely do this okay so we have so far uh I guess three props so
let's go ahead and go back to our prop types object so the first one that we'll
handle is username so we'll Define the prop name so username just like this and
you'll notice how as soon as I type username this lint ER this lint error
goes away okay so what we want to do is set the data type for username so we'll
do prop types so we're referencing the prop types import from up top over here
and then we're going to do do string so this basically tells uh JavaScript as
well as react that okay this username prop is a string and then we can
additionally also make this prop mandatory by adding this is required at
the end so do string do is required so it's pretty much chainable if think about it
like if you think of it like
this it's kind of like you're calling um a method and then that method returns um
the same instance that that method was called on and then you can basically call
the same method again so in this
situation we can call or not call but reference string and then reference is
required and then uh there's really
nothing else to reference anymore after that but um yeah you get the idea so now
watch what happens when I go
to the browser let me go ahead [Music] and open up the dev tools okay so watch
what happens if I do this let's say if I go back to app.jsx and if I don't pass
an username and if I go into the
browser if I refresh you're going to see that it gives us a warning the application
doesn't break but it gives
us a warning and it says failed prop type the prop username is marked as required
in user profile but its value
is undefined so this is basically telling you that you need to make sure you pass
in the prop for username so
this is good because if we don't pass in a prop for something that is required
then it's going to complain and notice how if I were to pass in anything but a
string so if I pass in an array whoops
let's go back to the browser you're going to see uh right over here it gives us a
warning a failed
prop type invalid prop username of type array supplied to user profile expected
string let's go ahead and pass Bob
back and that should fix everything so no more warnings good let's go ahead and
type I
shouldn't say type annotate I was going to say type annotate because I'm used to
typescript let's go ahead and add prop
or type checks for the other props so let's go ahead and type check age so we'll do
age and we'll do prop types so
this is going to be a number so there is is number right over here and then we'll
do is required and then we'll do the same thing for this call me function so
we'll do call me prop types Dot and then
there's this funk property and then we'll do uh let's see is required just
like that okay so now we are making sure that username age and call me all are
being passed as prop okay so these are all required now what
if you wanted to have a prop that was optional well you can do that so let's
say for example let's say this is logged in prop okay let's go ahead and add this
so is logged in we'll do prop types the type of this is going to be a bull or
boene so they have bull and then uh if you don't want it to be required in
other words if you want be optional then you just omit this is required uh right
over here so you don't
add is required okay you leave that out so now if I were to not pass is logged
in as a prop if I go back to the browser you'll see that we don't have any errors
but if I were
to add is required at the end you'll see that now it complains about the is
logged in prop because it is required so hopefully that makes sense okay now you
can also check the props for arrays as well so right over here I have this
favorite foods prop and this is an array and let's say I want to make sure that
this array has consistent values okay so
for this example right over here I have an array of objects let's add a few more
objects and let me also add another
property let me give this an ID and let me capitalize this and let me do the
same thing down here so let's do pizza and ID okay and I want to make sure that
this array has consistent objects so in other words I don't want this array to
just have a bunch of random elements in there I don't want this array to have a mix
of numbers strings blein objects I
want it to have only objects and I also want each object to be the same and have
the same Fields so what I can do is I can go back to my user profile and down over
here I
can add a check for favorite foods so favorite foods like this and then we'll
reference prop types and what I want to do here is I want to reference array of not
array but array of okay if you have
an array that you're passing as a prop that just has literally anything you want
and you only care that it's onr you
don't care of what the contents look like then you would use array so in other
words let's say if you're just
passing in an array and it has a number it has a string it has an object then
you could just use array okay array is good for just checking to see if the prop is
an array not for checking to see
if the contents of the array is valid or not so in our situation we want to use
array of and then this time over here
I'm going to actually pass in prop types. shape because we want we care for
the shape of our object over here so prop types. shape allows us to check for
a specific object and making sure that that object has a specific shape okay so
we're basically combining two things together so now what I'm going to do inside
when I call shape is I'm just
going to pass an object and then I can do the same thing that I've been doing up
top over here for these four fields
for the fields for the object so I'm going to specify name
and then prop types. string. is required
and then same thing for uh ID prop types
whoops prop types string is required just like this
okay it can look a little bit complex but just know that what we're really doing is
one we're validating the object
right over here that is inside the favorite foods array and then we're making sure
sure that this favorite
foods array is an array of all of these objects that have this shape okay so
hopefully that makes sense so now what I'll do is this so if I go to the
browser Let me refresh you'll see that we have no errors but notice what happens if
one let's just say if I pass
in an object you'll see that it complains because it is expecting an array right
over here it's saying that
it expected an array if I pass in an
array this works but let's say if I pass in an array with an empty object you'll
see that it now complains because although we do have an array with an
object with one element that's an object that object is empty but that object
does not take in the correct shape you can see that over here that the shape of the
object does not have the name
property that is required okay now now let's say if I add
the name property it's now going to complain saying that the ID is not there okay
so
we need the entire thing so let me go ahead and paste that back here and now
the errors are all gone but notice how if I remove ID from Just One of the objects
it's going to go ahead and
complain and also tells you the specific index of the uh array that it is having
an issue with so in this case you can see it says index one so that's this element
over here okay so now you know
how to validate uh arrays as well as validating the specific object for the
array itself so hopefully all of this makes
Children Components
sense now one thing that I want to quickly mention with our components is
that we actually have a parent to child relationship and we also have sibling
components as well so let me emphasize a
little bit about that because this is actually very important concept to understand
when it comes to developing
really any application okay if you understand objectoriented programming this is
something that should uh come
easy to you so right now we have our root component we have app now app has
one child component that we are rendering called user profile the moment
that you render a component inside another component which is what we're doing
right over here that immediately
creates a parent to child and child to parent relationship okay between for for
components so app has user profile okay if we go into the user profile component
we can see that user profile also has components being rendered as well we have two
components being rendered
inside user profile okay if I take away user profile if I don't render user
profile that means that user user username as well as user favorite foods these
components that are being rendered
inside user profile will not exist in the document itself unless if I explicitly
rendered those two components
directly inside the app component okay so user profile also has child
components as well it has user username as well as user favorite foods so that
makes user profile the parent of these two components and these two components are
children of
the user profile component okay and of course the hierarchy can go down infinite
amount of
times if user username had any child components being rendered then those child
components
would be children of user username and that would make user username a parent
component okay now because user username as well as user favorite foods component
share the same parents user profile this automatically makes them sibling
components the nice thing with sibling components is that you can share the same
props that were passed to its
parents so for for example all of these props username age
favorite foods and this call me function that I am passing down to the user profile
component all these props can be passed to both user username and user favorite
foods allowing me to
share those props between these two siblings now that's useful because
sometimes we may want to share very similar props between different components
maybe user favorite foods
needs the username as well as the user username component so we may want to
consider passing the username prop to the user favorite foods component as well
okay so hopefully this makes sense
later on you'll see more examples where when we work with State you'll see how
when I update one state variable you'll see how it will reflect all of the child
components
and The Sibling components as well okay and then I'll also show you how I can
update data from a child component and
have that reflect the parent component as well okay but I just wanted to go over
this very quickly because it is
something very important to understand in react but we'll dive deeper into this
when we get into working with with
Fragments
State now one more thing with components that I wanted to talk about are react
fragments this is actually something
very very important to understand in react and knowing when to use it is actually
very very beneficial for your
situation so right now all of our components have one root element that we
are returning remember what I said a component is a function that returns a
jsx element or Js B expression in this situation we're returning a div and this
div can have as many HTML elements as we want however if I remove this div right
over here you see that it actually errors out and it's complaining saying that we
must have one parent element
that's because by default I can't just return two HTML elements just like this okay
now you might be wondering well maybe you might want this bold element as well as a
span element to be rendered to the
document and uh let's say for example this user username component is being
rendered inside user profile you might
want these two elements to be immediate children of uh wherever this component
is being rendered so it's being rendered right over here so you want those two
elements to be immediate child elements
of this div right over here okay now how
can I achieve that without needing to write wrap them inside a div right because
the moment that I wrap it inside
a div it becomes a child element of the div now it still technically is a child
element of the root div the outer div that where wherever it's being rendered
but sometimes having these elements being wrapped inside a another element
can break CSS or it can break your selectors for example you might have
specific selectors that you're using that need to Target IM immediate child
elements okay so I'm just using that as
an example so what we can do to add these two elements to the document
without needing to add this div is use a fragment and it's actually very easy to
use so there's two ways that you can use a fragment syntactically so the first
way is you can do it like this you can reference react. fragment just like this
whoops
fragment and then you want to make sure you close that as well right over here okay
we do
need to import react up top over here so import react from react okay and now
notice what happens
in the Dom tree so if I were to go back to my browser and if I
expand the HTML elements you'll see now
we have both of our elements that are from user username component and they don't
have that root
root div anymore and they're immediate children of its parent components root
element also known as uh the user profile component okay they become
immediate child elements of this uh div with this user profile ID okay you can
see that right over here if I remove this react fragment and if I change it back to
a
div you can see that that div gets added to the document and it's wrapping both
this bold element as well as this span element right over here okay and again
there's no right or wrong answer it's really up to you on how you want to structure
your
HTML remember there's no right or wrong answer with HTML and CSS it's how you want
to structure things I'm only
showing you this because you might have certain needs that might make it so that
you don't want this div to actually be
added to the document because of styling issues or maybe you might have specific
selectors that you need to Target get uh
this bold element as an example and you cannot have this div right over there
okay so using a fragment would solve that issue now the shorthand way to use
fragments is actually instead of just using react. fragment you just use an
empty tag just like this okay so you literally just do angle brackets you don't put
anything in between and then
you close it just like this so angle brackets and then put a forward slash and then
you're done and that's literally a fragment a Shand Syntax for
fragments and it does the same exact thing okay if I were to go into user
profile I can literally remove this div right over here and wrap all of these
elements all of my components and elements in a fragment and if you see right over
here now all of these
elements are immediate uh children of this div and that div is this div right
over here which is the root element of app okay
since user profile is the only component that I am rendering I can actually just
remove this div and now we can see that all of uh
these elements are immediate child elements of the root div which comes
from our entry point right over here okay so hopefully fragments make sense
and again there are many different ways that you can use fragments like I said you
can use the group components together so if I wanted to just render
uh let's say for example I want to render user username with user favorite foods
together I can group some I can
group them together just like this with a fragment and I don't need to worry about
adding an extra HTML node to the document not that this would really change
anything in terms of your tree
structure for your uh for your application but um it is a way to group stuff
together so I just wanted to
mention that okay because sometimes like I said you want to group elements together
you want them to be all grouped
together but you don't want them to be wrapped inside a div because that div could
uh let's say uh put them all in
the same row or maybe it might put them all in the same line whatever is it could
break CSS so using a fragment
could help in some situations again this all primarily depends on how you structure
your CSS so you have to make
sure you understand okay what exactly is my CSS targeting and should I use a
fragment for this to achieve what I want
to do so hopefully react fragments make
Styling with CSS & SCSS
sense all right so now we're going to go ahead and talk a little bit about styling
in react so this is just going
to be a short little section we're not going to go in depth on CSS because this is
not a CSS tutorial but I did want to
show you how to at least style your react application as well as style components
so we're going to start off with some basic CSS files so what we'll do is
we'll apply what's called a global style so a global style basically just means
that you want to apply your Styles globally throughout your entire application so
literally everywhere so
in other words let's say for example I want to apply a global background maybe
I want to apply a dark color background everywhere throughout the application so
how would I do that
well in order to apply a global style we want to make sure that we have first a
CSS file so I'll create one uh let's create a new file we'll call this
global. CSS okay and this is where all of my Global CSS will be defined so uh
what I want is I want to make sure I have a dark background color so what I'll do
is this we'll start off with a
body tag and then we'll do background color and then let's
do uh let's start with 0000 and I'm going to use this VSS code feature to
kind of like change the background color so I'm going to use 1 e 1e 1e and then I
also want to change the text color to be I guess white maybe not white but just
like a slight light color so that way we can actually see the text and now to
apply the CSS to our actual application because right now it's not being applied
what we need to do is we need to go to our entry point of our application and we
just want to
import that global. CSS file just like this and now you'll see that the CSS is
being applied to our application we basically inverted the colors we made the text
white and we made the
background dark okay so that's how you can apply Global CSS so this is I would
recommend you set things such as the font family so if you wanted to set a font
family you could do that right over
here so let's say if I wanted to set it to I don't know um sand
serif maybe I don't maybe I don't have that font oh right there okay there we go
the font just
changed okay uh if you want it to set let's say uh you can also set like a
height as well set the height to 100% and B basically any uh any Global
CSS you want to put inside this file okay let's talk about component level
CSS because obviously we have our Global CSS but then we have our components where
we want specific CSS applied to it
okay so let's say for example maybe for
my let's do user username okay let's say for this user username component I want
specific CSS applied to uh the font to the color the text whatever it is right
I want to make sure that I'm applying it only to this component and not globally
throughout the entire application okay
so what I want to do is this there's two ways that I can do this one I could just
do an inline style so I'll show you how
to do that so let's say if I wanted to change the font size of this uh of this
username text
I can just go to the tag itself and I can do style and then equal sign and
then you want to provide a pair of curly braces so with inline styling in react
it's way different than how you would write it in just regular HTML so in
react you want to actually pass an object into this object over here or into this
pair of curly braces right
over here just like that and basically this object will have all of these CSS
properties so for example if you wanted
to apply the font size you would just do font size and it could pass in the string
so let's do
32 and now if I go to the document you can see that let me just make sure I'm not
zoomed in oh I was zoomed in let me
see let's change this to oh it should be 32 pixels sorry about that so now I can
see that it is being applied to the
username text and if I look in the dev tools you'll see that this uh this B tag
right over here has this style attribute and then it has font size so again this is
how it would look like in HTML but in
react you want to make sure that you applying it inside this object right over here
if I want to change the color
I would just do color and then I want to set it to let's say uh maybe a red color
like that and then that would be applied right over there okay so that's how you do
it in line uh let's show you a couple
more examples there's also let's see um there's font size font family
maybe you don't like the default font that we set globally so you can do something
like cursive and then I'll
change right over there okay there are a bunch again you can just go through
intellisense and look through all the other ones um but if there's one that you
want and you know the name of it
just remember that it's the same name as it is in just a regular HTML attribute you
just need to make sure that you're
using a camel case so notice how in HTML right you have uh let me show you you
have font hyphen size that's how you would write it in just regular plain HTML but
in react or in jsx you would
write fonts and then capital S size and no space or no hyphen at all just like
this okay and then you want to make sure it's inside the object so hopefully that
makes sense so now let me show you how to do it not with in line but at the
component layer with an actual CSS file so what we're going to do is inside our
components folder I'll create a new file and I'll call it styles.css
and what I'm going to do here is just create a class so I'll call it username
and I'll just give it the same Styles and remember this is a regular CSS file so
you're just going to write CSS
regularly so instead of font size like this where we did that in the jsx we're
just going to do font pyth and size and 32 pixels set the color
to Red now we're going to go back to our user username component and then
here I want to import this styles. CSS file that I just created so we're going to
import it like
this import pair of quotation marks and then the relative path styles.css
and then if you look in in the browser nothing has changed so far with the
username and that's because we need to make sure we apply the class name to uh
whichever tag we're trying to style okay it's exactly the same way that you would
do it in just plain HTML so I want to
style this uh bold tag this B tag so I'm going to give it a class name so we're
going to use this class name attribute in regular HTML it's just class but in
jsx it's class name okay and this is where you're starting to realize the
differences between htl and jsx even
though again 95% of it will look identical there are still a lot of things that are
different actually I I
should say 90% so we're going to do class name equals and then now just the name of
the
class so the name of the class is username so we'll just do username just like this
if I save you're going to see
now we see the style is being applied to username it has a fun font size of 32
pixels and then the color is red and you can even look in the dev tools we should
see this right over here so this element
this bold element has a class called username and when I click on this you can see
all the styles that are applied
to it okay now one more thing that I do also want to mention too is even if I
were to let's say go into this styles.css file and let's say if I uh
modify the body CSS okay so let's say if I do body and then background color let's
do uh let's
do Aqua okay if I refresh you'll see that it actually does not get applied to
the actual document itself now I want to show you as well right over here if I go
to
body you'll see that in the dev tools it actually shows uh two body tag Styles
okay and this one right over here is actually just being ignored you can see it's
it has this line struck through
this one over here just means it's being ignored because we have this one
overriding it basically okay if I were
to remove this background color style okay and sometimes you do need to
make sure you refresh as well because it doesn't actually reflect properly but this
time I can see that it is properly
being reflected you can see over here that I am setting the background color to
Aqua because in the global Z CSS file
my root CSS file I am not setting that CSS style in the body tag okay but since I
said over
here it's not going to overwrite it I could overwrite if I wanted to by just using
the uh exclamation mark
important and then now you can see that it is being overridden okay so hopefully
this makes sense I do also want want to show you one more way on how you can
write CSS as well as style your components using CSS modules okay and
CSS modules are actually very very common a lot of people actually like using CSS
modules because they're more a
prone to uh less issues when it comes to styling your components because one they
are locally scoped to the component okay so here's what we're going to do I'm
going to go ahead and rename styles.css to styles. module.
CSS and instead of importing it like this I'm going to go ahead and actually import
it like this we'll do import and
we're going to give it a name so import Styles and then from and then the relative
path styles. module.
CSS now what I'm going to do is instead of actually just passing in the class
name at as an actual uh string we're actually going to use a
pair of curly braces and then we're going to reference Styles as if it was an
actual object and then reference
username as if it was a field on that object okay so what what really happens
is this Styles this CSS module basically takes all of your
fields and then it kind of like just puts them in an object and you can reference
it as an actual property
itself and then use that to apply the correct class to the element
okay so I'm going to save and Let me refresh and you'll see
now if I go to here you can see I have my B element right over here my bold
element and you can see the class name is not exactly username but it has like this
underscore username and then some
autogenerated text right over here or this hash okay so it's not the exact class
name
but it is uh applying the correct CSS styling which is what we want okay and
this is what a lot of people prefer to use when it comes to styling because one
it's again locally scoped so you don't
have to really worry about your CSS conflicting with other components now many of
you may be
familiar with a CSS preprocessor called SAS now there are plenty of CSS
pre-processors out there but SAS is one of the most popular ones so I'll show you
how to actually use it
it's actually very easy um so what we want to do is go into our project terminal so
in the directory
I'm going to go ahead and install the pre-processor so you need to make sure you
install the pre-processor before you
can actually use it so since we're using vit it actually supports uh SAS out of
the box or scss um if you're trying to use a different pre-processor definitely
make sure you check the V docs first to see if it supports out the box and see
if there needs to be any special configuration so I'm going to type npmi
hyphen D and then SAS just like
that okay there we go and then let's just run our project
again now what I can do is create an sc CSS file so I'll just create a new file
I'll call this a users. module. sccss you don't have to
use uh CSS or scss modules you can just use um just a regular CSS file it
depends on what you prefer not Everyone likes to use CSS modules or scss modules
some people just prefer using a regular stylesheet and then importing that and then
using the class name as a string
literal it's up to you that's why I'm showing you all these different examples so
inside um my scss file I'll just
write regular CSS I'm not going to go in depth on uh using SAS but I'll just do
uh let's do this let's see what else can I style um maybe I'll style uh favorite
foods so uh Foods title and let's do
font weight bold then font size 64
pixels just as an example and uh since I'm using a CSS module I don't want to have
hyphens in my uh in my class name
so actually I'm going to use camela case for the class name since I am using a CSS
module
okay so we'll go to let's go to user favorite foods so
here I want to style this text this span element so I'm going to first import my
scss module so import users I'll just call it styles from users.
module. scss and then I'm going to go ahead and
add the class name attribute and then I'm going to provide a pair of curly
braces so class name equals curly braces and inside Styles Dot and then the
name of the class so foods and then title just like
that so Foods title and then now we should see it is being applied properly
now if you do prefer to use a kebab case which is what this is known as where you
have this hyphen in between each word
you could use Kebab case but do note that uh you will need to use square bracket
notation to access the class so
you would have to do something like this Styles and then square bracket and then
Foods title just like that okay it's up to you
on what you prefer to do do I personally don't like using um square bracket
notation to access properties sometimes you may need to especially if you're using
Kabab case it's totally up to you
but um hopefully this all makes sense so yes you can use SAS and any CSS pre-
processor that you choose
Dynamic Rendering Lists/Arrays
to in this section of our react tutorial I'm going to teach you how we can take an
array of elements or a list of el
elements I'm going to use those two terms interchangeably and I'm going to teach
you how you can transform each element
from a regular plain Json object to a jsx element so that way it is actually
renderable to the document it's important to understand this part because when you
have an array of Json
objects which you're going to a lot of times especially if you're fetching data
from an API you cannot just take that
plain Json object and plug it into your jsx code and have it render to the
browser doesn't work that way because the browser needs to be able to render
something that's renderable and a plain
Json object cannot just be rendered to the document as is you need to take it
and then transform it into a jsx element
okay so I'm going to teach you how to do that we're not going to be fetching data
from an API but later on you will learn
how to do that and you'll be able to apply what you're learning in this section
with fetching data from an
API now I did went ahead and actually cleaned up our code a little bit I deleted a
lot of the previous code that
we wrote In fact deleted everything and I'm going to create a mock array so I'll do
that right now so
cons uh mock users and this will be an array and what I'll do is inside this
array we're going to go ahead and just create some plain Json op objects so
this is going to represent a user an array of users so I'll just give it an
ID of one and then I'll give it a username and let's just do email address
we'll keep it very simple okay and then I'll uh I'll do one
more so we'll have two users and then we'll do uh username Michael and then
we'll do Michael Michel or for email do Michael an.com
so now I have two users and again pretend like this data is coming from an API okay
even though right now it is
mock data it is local data but pretend it's coming from an API because
realistically when you fetch your data from an API this is what it could look like
okay if especially if you're
fetching an endpoint that returns multiple elements so if you if you're
fetching an endpoint that gets you let's say 10 users at a time then you will
have an array of users okay so what we're going to do is we
want to render all of these users to our document okay because right now if I try
to just uh let's say if I try to do this if I try to do mock users just like this
right and if I go to my browser
nothing's going to happen uh let me just make sure app is being rendered it is okay
nothing is going to happen you're
you're seeing I'm trying to evaluate this array and the browser is clearly not
showing anything and you'll see that
right over here in the in the logs uh let me actually refresh okay so we have a
bunch of errors and it's
saying that objects are not valid as a react child okay and that should make sense
because right now we're working
with an object mock user which is an array which is also an object and then
inside this array we have plain Json object as well so we can't render this as is
and that's the reason why it was
giving us all of those errors so now in order for us to render all of these objects
to the document we need to take
our mock users array go through each elements and transform each element from
a plain Json object to a jsx element which is something that is renderable to
the browser to the document and the easiest way to do this is to use a prototype
function on our array called
array. map so if you look over here we have our mock user array I can actually
call this map function right over here and some of you may be familiar
with this map function already if you are that's great if you're not I'll explain
briefly what exactly this
function does so basically this map function can be called on an array and
it applies a transformation on all the elements in that array and it returns a
new array with each element transformed okay so it's just better if I just show
you an example instead of just you know just saying a bunch of things so what I'll
do is I'll go into the node shell
right over here and what I'll do is I'll Define an array right now so I'll just
call this numbers and then we'll do uh 1
2 3 4 5 just like this okay so I have an array as you can see over here and I
have five elements all numbers what I want to do is I want to take each element in
this array and I want to
multiply each uh well actually let me say it like this I want this array to
have each element multiplied by five okay so I want it to uh I want each
element to be uh let's say for example for one will be five two will be 10 3 will
be 15 4 will be 20 5 will be 25 and
Etc okay so I'm going to go ahead and reference numbers and I'm going to call this
map function now this map function
is going to take in an argument which is a callback function okay and you should
be familiar with callback functions you can also call this a transformation
function okay so if I use uh both those
terms interchangeably just know that I mean the same thing okay so this callback
function is a transformation
function and the reason why it's called a transformation function is because one
this callback function takes in it takes up to three arguments the first argument
is going to be the element of the array
the current element of the array that we that we are trying to transform okay so
what really happens underneath the hood
when you call map is it actually iterates it Loops through all of the elements in
the array every single
element is going to be processed okay so the first iteration um the argument numb
will be one the second iteration the argument numb will be two and so on and so
forth
okay so we're going to take that element that is in the array which is
given to us the argument numb and what we want to do is we want
to take this argument and I want to multiply it by five and you don't have to
multiply by five you can literally
apply any transformation you want you can add one you can divide you can
divide it by let's say uh let's say 10 you can uh subtract you can do anything
you want you can even parse to a string if you wanted to basically anything okay
what I'll do is I'll multiply by five just like this and this value this new value
so num * 5 will be returned okay
and what happens is this new value will be returned um and it will be appended to a
new array because it doesn't modify the original array itself okay so it will be
appended to a new array and then if I hit enter you're going to see right over here
that I actually get a new array
outputed to our a console and you'll see that every element in the numbers
array is now multiplied by five and the one thing to note is that the original
array itself is not modified so this map function is immutable and what that means
is just basically doesn't modify
the original array itself or the original value itself so it creates a new array
with all the transformed
values okay so hopefully this makes sense and there are plenty of examples
that you can see online as well I really encourage you to uh look up this array.
map prototype function and really
understand it as best as you can because if you don't you're going to have a hard
time continuing with react because
you're going to be using this uh array.map function literally all the time okay so
hopefully this makes
sense so now what I'm going to do is I'm going to go back to my code and I'm
going to uh again call mock users. map so we're calling this map function and
remember that we want to uh pass in a callback function aka the transformation
function so I'll do that right now so this is my callback function and
remember the Callback function takes up to three arguments the first argument is
going to be the current element that we
are trying to process so in this case I'm going to call it user because it
represents the user object itself so
inside uh this callback function right over here I can reference user user uh and
all of its properties so I can
reference ID email uh username any any field I want okay and you can see
intellisense was was picking up those uh Fields but what I want to do is I want
to make sure that I am returning a value you always want to make sure that you
are returning a value because if you don't if you don't return an explicit value by
default array. map will just
return an undefined value okay so what we want to do is we want to return jsx
okay because whatever you return is basically what is going to be uh returned into
that new array so we want
to return jsx so what I want to do here is I want to basically have uh something
that is
valid jsx and that could be you know a component it could be uh HTML anything
okay so I'm going to go ahead and just return to div just to keep things simple
and what I'm going to do is I'm going to take each uh
field in the user object and I'm going to Output it to uh the Dom by evaluating
each field so for example let me do this I'm going to go ahead and use a bold tag
and I'm going to render the username like
this so I'm going to reference user. username
okay and then I'm going to use a a Break Tag so I can go on the next line and
I'll do the same thing for
email and I'm going to do user email just like that okay and I'll actually do
one more for the ID so I'll do that before the username so ID and then span user.
ID just like this
oh let me also make sure I have the Break Tag as well whoops okay let me also do
the same thing for
down here okay right now we have a bunch of red squiggly lines a bunch of uh
linting issues I'll address this in just a bit don't worry about it for now but I
want to show you what happens if I go to the document and you'll see now if I
refresh you can see that we are now
displaying all of that data in the document okay so just to kind of like
recap What's happen happening we're basically transforming each Json object that is
a
user to a jsx element because we're returning
basically this jsx element that is renderable okay and it's just a plain
div right over here and remember that we can render divs to the document itself
okay so what happens is we are transforming this mock users array of
objects to an array of jsx elements and in fact if I actually did this let me do
this if I were to console log this whole thing right over here and
if I go to the browser the browser tools and if I were to expand this you'll see
that the
elements are now an array of uh react elements you can see the type of is this
symbol react. element Okay so it's no longer a plain Json object it's an
actual react element okay and the react will take care of going through each uh
element inside this array and uh taking that j6 element and rendering it to the
document so you don't so it takes care
of that part for you you just need to make sure that it is an element that is
renderable okay so hopefully this makes
sense so let me go ahead and uh just copy this and remove this console log I want
to go back to addressing this issue
where we have this uh linting issue right over here so it's telling us that we're
missing a key prop for the
elements in iterator and you're probably wondering what does this even mean okay
so whenever you are dealing with rendering lists or arrays of elements to
the document so right over here this is what we're doing we're trying to render an
array of users we need to associate each
element that is being rendered to the document with a unique value okay so in
this situation right over here you can see that we are mapping this mock users
array okay we're
taking a total of two users transforming those users from a plain Json object to
a jsx element which in the end it gets rendered to the document and we see two
divs that are added to our document if I go to the browser if I were to uh go to
elements and let me just kind of expand the tree right over here you'll see that
we have a total of uh two divs right here we have this div and then we have this
div right over here we have two
divs total okay and you can definitely assume that if we had let's say 10 users
then you'd be correct that there would be 10 extra divs or I'm sorry not 10 extra
divs 10 divs total added to the
document all of which represent a user element now we need to make sure that each
one
of these divs and it's not just a div it whatever your root element is so for
example if this was a
section uh if this was a section if this was a nav if this was any HTM element or
even
a component which I'll show you how to do that in the next part you need to make
sure that this element has a unique
key the reason why this is important is be is because react needs to use these
keys to keep track of how these elements are being appended to the document as
well as being removed from the document now you know in if your application is very
simple you might not really notice
much of a difference or you might not even notice the issue right away or at all
but down the road as your
application gets more complex you're going to run into weird bugs where let's
say for example if you try to remove an element and then add the same element
back again you're going to see that the order is going to look very weird Okay
so that's just one example of a potential problem that you might run into there are
a lot of other issues too
that could happen so it's very important that you have an Associated key with
your elements it's very easy to do that what you do is you just use this key
prop right over here or this attribute we're going to call an attribute because
we're just using a regular div so you're
going to pass pass in this key and then you want to make sure you pass in an actual
unique value okay so what you
want to do is look at your resource and you want to ask yourself okay what field
can I use that is actually guaranteed to be unique so for example I have this ID
field and majority of time you can always make this assumption that this ID is
guaranteed to be unique especially if
you're using a database and your database is auto incrementing your unique IDs so
it goes
from 1 2 3 4 5 6 7 8 9 10 and so on and so forth you can assume that this ID will
always be unique okay there might
be some situations where you might not have a unique key or a unique ID that
you can use and in those situations you might want to generate some kind of hash
we're not going to talk about that in this section okay but for now we'll keep
things simple and we know that this ID
is going to be unique so what we're going to do is we're going to pass in user ID
as a value for this key
attribute and now you'll see that this error goes away or this warning goes away
and if I go back to the
browser all of my errors are gone or all of my warnings are gone okay and
Visually you're not going to notice any difference at all and even if you inspect
your uh your browser tools if
you go into the tree what I'll do is inside uh the browser tools right over
here I'm going to go to this div and then I'm going to highlight it and if I go to
properties you're going to see
that right over here that this react fiber property over
here you'll see that it has this key and the value of it is one if I go
to the next div right over here this one okay same
user element and if I were to look at the properties you'll see that the key is two
okay if I
were to add more users so let me do this real quick I'll just add two more users
I'll change the
ID to three and four respectively you'll see that the other
divs right over here will have a key of three and then this one will have a key of
four okay and underneath the hood
react will use these keys to keep track of each element again there's a lot of
reasons why you need keys we'll probably dive into this topic uh in a separate
video but just again remember that you always need to make sure you are assigning
keys that are unique whenever
you are rendering lists of elements okay and just to show you what happens if I
were to have let's say two
elements with the same ID you're going to see that react is actually going to
complain it's it's going to say
encounter two children with the same key for and it says Keys should be unique so
that components maintain their identity
across updates and this should make sense because again when you're trying to add
or remove elements react needs to
know which element that needs to remove or ADD and having the same key is going
to create conflict okay so now instead of actually just returning a div and
then having all of this uh jsx inside this div over here here we're actually
going to move all of this code into its own components okay and this will teach
you the basics of reusability while this does work we want to make sure that
we're keeping our code more organized and clean and more readable okay and the
purpose of this is because for example yes this does work we're rendering all of
the data to the document but we
always want to make sure that we are creating components that represent the
resource that we are trying to render to
the document okay so what we'll do is instead of rendering or instead of just
returning this div I'm actually just going to return this user details component
which we're going to build out
so let me do this I'm going to just copy this right over here and I'll delete this
div over here and what I'll do is
I'll go into the user details component and instead of returning this fragment I'm
going to return to div and
let me paste all of this code that I just copied from right over
here so it's going to look pretty much the same thing as what we had before the
only difference is that it's encapsulated in its own component in its own user
details
component Okay now what's important is that inside this user details component
you can see that we need a reference to the user's ID the user's username as
well the user's email so this should spark the idea that we want to make sure
that we are passing those fields as props to the user details component okay
so now what we're going to do is we're going to return user details just like this
okay
so return user details with the angle brackets and then we need to make sure
that we're still passing in a key so let's passing that key and we're
going to use user. ID and let me just fix this real quick let me just change this
from ID 4 to
3 and uh now we need to also make sure oh whoops I need to import the component up
top over here let's do that import
user details from the user details file okay
so let's also make sure that we're passing in the necessary props so what
I'm going to do is I'm going to pass in this user argument that we're we're getting
from the Callback function that
we passed to the map function remember this user argument is the uh user itself
in this mock users element we're going to take that user and we're just going to
pass it as a prop to user details
okay so we're passing the user object into the user details component so let's do
that so user we're
going to call the prop user and then we're just going to pass in user just like
that okay so we're
passing an object to user details now we're going to go into the user details
component and we need to take in
the props as an argument so we're going to add props as an argument to this
function right over here and now props
is an object that's going to have this user prop as a field so if I were to
conso log props like this you'll see that when I
refresh uh you'll see that right over here on line two which is where we are
logging the props over here it has this
user field and that user field is an object with all of its Fields okay so
what I'm going to do is I could do a lot of things I can either just reference
props directly and then just reference user. ID for everything and this would
work just fine and you'll see that everything is going to be rendered to the
document
just fine we're getting these linting issues because we have hav't done prop
validation but this works just fine or
the other thing that you could do and I recommend doing this is actually just
destructure the prop itself in the uh
argument signature so what I can do is instead of just doing props do user for
everything I could actually just
destructure it like this so I'm basically unpacking the user field from
the props object in the functions argument signature right over here okay
and then what I can do is I can reference user directly like this instead of having
to reference props do
user and then it works the same exact way okay now let's go ahead and just
very quickly add the prop validation might as well so now you can see that we're
pretty much taking everything that
we've learned from the previous sections and we're putting everything together so
let's add prop validation so we'll do
user details. propop types and remember P right over here is a
lowercase and then we need to validate the prop itself which is user remember
we're only passing in one prop to the user details component we're not passing in
each uh element or each uh field in
the user object individually you could if you wanted to I think it's just easier
just to pass the entire object as
a whole okay so we'll reference user just like that and then we're going to
reference prop types and then we're going to use the shape function to validate the
shape of this user object
so this is how you can actually validate objects okay so we need to make sure we
validate the ID so ID is going to be a number so we'll do prop types. number is
required username needs to be validated so we'll do prop types username is a
string and then is required and we'll do the same thing for email so email prop
types do string is required okay and now you can see that
the linting error linting errors go away if I refresh no errors in the
console no warnings in the console and if I were to remove email from one of these
objects you'll see that uh it's
going to go ahead and give us a warning because one of our objects in the mock user
array did not have an email field
to find okay and that's the reason why it's giving us this failed prop type warning
so hopefully this makes sense so
now you you can see this is a lot more cleaner than what we had originally
you're encapsulating everything in a single component and what's nice is that
let's say for example um you might not necessarily uh render an array of jsx
elements to the document but you might want to render an individ idual user to
the document itself and having this user details component allows you to reuse
this component because all you need to do is just get the user an individual user
and you can fetch that from your
API right assuming that you have an endpoint that retrieves a single user you can
pass in the user object and then
render all of these details to the page or to the document itself okay so this
allows you to reuse this component over and over and over again so you save a
lot of time from just you know manually rendering a div and writing out all of
these tags and you know rendering each
uh field so hopefully this makes sense okay and other things that I would
mention too is that this enables you to properly encapsulate uh State especially
when you
need state for your components we haven't talked about State just yet but we will
get to that later on in this
tutorial but it's just something something to
Conditional Rendering
consider in this section of our react tutorial I'm going to teach you how to
perform conditional rendering now the
term itself should give you an idea of what exactly it is you should already know
what conditions are in programming
but essentially whenever you are rendering elements to the document you want to
often times control
what the user sees based on some condition and that condition can literally be
anything it can be if one
is equal to one if one is not equal to one it can be if the user is logged in a
common use case in the real world is checking to see if the user is authenticated
and if they are you may
redirect them to their personalized dashboard if they're not logged in then
you don't want to render to them or give them access to certain pages or
components that are supposed to be protected so in that situation you would want to
render either let's say a login
form to have them log into their existing account or a registration form to create
a new account so this is a
common example of conditional rendering working on the frontend side there's a
lot of use cases with conditional rendering so maybe you want to conditionally
render a banner on your
marketing website to display a coupon for new users only okay and oftentimes
websites will use cookies to check to see if the user has visited the website
before or not so if the user has never
been on the website then they'll check to see if that cookie exists and if it has a
value and if there is no cookie
then that means the user has visited for the first time or they may have just
cleared the browser cookies in that
situation you would want to conditionally render a special Banner that gives them a
coupon let's say 10%
off of whatever product it is that you're selling so that's that's just another
example of using conditional rendering I'm sure many of you will be
able to come up with a bunch of different ideas when it comes to rendering elements
to the document based
on some condition so enough talking let's go ahead and actually take a look at some
examples so inside my main app
component what I'll do just to start off with a very basic example I'll go ahead
and
display a message conditionally to the user based on their authentication status so
we're going to create a fake
variable called is authenticated I spelled that wrong authenticated I'm going to
set this to
true and what I'm going to do is I'm going to write a conditional statement
to check the value of is authenticated and the first way that I'm going to show you
is going to be a very easy way where
we use an if else statement and then the second way that I'll show you we're going
to use a Turner operator which is actually more common so what I'll do is
I'll use a regular IFL statement so if and I'll check my condition so is
authenticated okay so if is authenticated if it's true then it's
going to execute this block of code inside this curly brace so all we want to do is
just return jsx so again you
should already be familiar with returning jsx in your component the only difference
here is that we are
conditionally returning specific jsx based on whatever the value of our
variable is is authenticated is so I'm going to go ahead and return to div and I'm
going to also have an H1 tag inside
and I'll just say welcome user okay if I go to my browser you'll
see that it says welcome user now let's say for example if I were
to change the value of is authenticated from True to false you'll see that now
the browser does not display welcome user now it should be obvious because is
authenticated is now
false so this block of code does not get executed so it never reaches this return
statement and we're not returning anything after this check so that's the
reason why it's currently just a blank page so what I could do is I could
actually just add an else an else block over here and I could just return
another div and I'll just say you are not logged in I could wrap this in an H1
tag as well I'll just do a span tag and now you'll see it says you are not logged
in now you don't really need this
else case you can just actually remove that and just straight just return this dat
right over here because if is
authenticated is false then this block is not going to be returned or this uh
this line of code is not going to be executed and then we're just going to just
jump to this part and just return
this default message if the user is not logged in okay and that's literally it
when it comes to conditional rendering you just have an if condition and then if
you need let's say an else block you
can have the else block if you need else if to check to see if the value is equal
to something else you can add an Els if as well okay now I'm going to show you
the more common way to actually write this so instead of using an actual F else
statement we're going to use a
Turner operator okay now turn operators may be something that you may not be
familiar with especially if you're just new to programming but you should
definitely learn what Turner operators
are because you're going to be using them everywhere in literally every single
react project okay if you work on
an open source react project you're going to be seeing them everywhere whenever it
comes to conditional
rendering so the easiest way to explain what a tary operator is and how it looks
like is just by showing you some
documentation now this is what a tary operator looks like you can easily get this
page by just Googling tary operator
and it should be like the first or second result on Google okay so
basically a Turner operator is also another conditional operator as well and it
basically takes three operand okay so
this is what it looks like right over here let me zoom in just a little bit so
right over here we have our tary
operator and we have three oper we have the condition and then we have the two
values that will be returned based on the uh conditional value so the way that
it looks like is you have your condition and then you have this question mark
okay on the right hand side of the question mark this is where you want to place
the values that you want to return
based on the condition so for example is member is going to be a true or false
value it's a conditional value so if is member is true what's going to happen is
it's going to return this value over here $2 which is on the left hand side
of this colon symbol if is member is false it will return $10 so whatever is
on the right hand side I honestly think this is the easiest way to understand turn
operators so just remember that you
have this question mark on the left hand side of the question mark you have your
condition and then on the right hand
side of the question mark you have your two other oper where you're going to return
a
value right over here on the left hand side of the colon if is member is true
and if is member is false or in other words if the condition is false then it's
going to return whatever is on the
right hand side of the colon okay so I just recommend you practice turn rate
operators because you're going to be using them a lot but hopefully this makes
sense so we're going to go into
our component and we're just going to go ahead and write the same logic that we had
previously but using a Turner
operator so we're going to use the return keyword and remember we need our
conditional statement so the first thing that I'm going to do is reference is
authenticated because even though this itself is a variable that is a literal value
true or false it still is a
conditional statement as well so return is authenticated and then we need our
question mark symbol and then on the
right hand side of the question mark we want to set up our two operand okay so the
first operan is going to be what is
going to be returned if is authenticated is true so that's what this div with the
H1 tag will be and I'll just say welcome user okay now I need my colon and on the
right hand side of this colon we're going to go ahead and return the div
with the text you are not logged in and this div will be returned if is
authenticated is false okay so this is literally what it looks like as a tary
operator or in the form of a turnning operator if I go back to my browser
you'll see that right now it says you not logged in and that's because is
authenticated is false so when we go to
our tary operator over here is authenticated is false okay so it's
going to go ahead and return what is on the right hand side of the colon so dis
right over here with the H1 tag that
says you are not logged in if I go ahead and if I change is authenticated's value
to true now it's going to go ahead and
return what is on the left hand side of this colon so it's going to return this
div with the H1 that says welcome user and if I go to the browser you can see
that this is what is being displayed to us so hopefully this makes sense now so
far the examples that I was showing you uh dealt with values that only had two
possible values either true or false and that's pretty simple but sometimes you
might want to check the value of a
specific variable or property on an object that may have more than two
possible values okay so a good example example of this would be let's say you're
building a system where you have a user and they have different statuses okay so
the user status can be uh not verified which could mean they didn't verify their
email or their phone number and
then the other status can be verified which means that they verify their email or
their phone number and then the other
status could be account disabled which means that the user disabled their account
so they no longer want to be
able to uh you know actess access the account unless they reenable their account
again so in this situation we
have a status that has three possible values there could be more there could be
four five or six or maybe even seven
different statuses it's just up to you and your implementation so what I'll do
is I'll declare a variable and I'll call this user status okay and then what I'll
do is I'll just set the value currently to not verified now I'll just leave a
comment
up top over here just so we can uh remember what the values could
possibly be of user status so do not verified verified and
account disabled okay now in a situation like this we'll definitely need an if and
else if statement as well because before we only did an if and then an else
statement we didn't do else if so what
what I'll do here is I'll check to see if the user status is is equal to not
verified so if it's equal to not verified then I will return and you
guessed it some jsx so this will be a div and we'll just simply use a span tag
and I'll just say or not verified please verify your email
or mobile number okay and then let's go ahead and check
to see if the user status is verified okay so else if user status
equals verified so if the user status is equal
to verified then we can display to the user let's say their personalized
dashboard we can display you know a confirmation screen saying that oh you now
verified whatever it is whatever
makes sense to your application of course okay I'll just display something simple
I'll just say you are verified congrats click here to access
your dashboard obviously we don't have a dashboard built out so I'm just going to
write some text and then now we need to
check for the third status the third possible value of our user status
variable which is account disabled okay so in this situation I actually have two
options okay since I've already handled not verified and verified I've already
checked to see if the user status is verified or not verified so if we 100%
know that these are the only possible three values then I can actually just use an
else case right over here and
this kind of just acts like a default case right which means which implies
that the status is account disabled personally I don't like doing this because I
like to be explicit with
checking my value use but if you want to just use an else case that would work just
fine because at this point we
already know that the user status isn't not verified it isn't verified and that
leaves us with only one other possibility which is accountor disabled now you might
have a situation where if
you're building your application and let's say you don't set a status on the user
you might set it to null or
undefined then you definitely will need to check uh with an lsif case you need to
check the user status
if it's equal to account disabled and then you can have an else case also known as
the default case which handles
when the user status is null okay so I'll actually show you um both scenarios
so right over here in this else case I know that the value is going to be account
disabled if we reach this block
so I'll just go ahead and say your account is disabled okay now let's go
back to our browser and let's take a look at all of the possible scenario so right
now it says
you not verified and that's because our user status is equal to not verified if
I change the value of this variable to verified you're going to see now it says you
are verified
congrats if I go ahead if I change this let's if I just set this to
null okay so since I'm setting user status a null that means this condition
is going to fail user status equals to not verifi that's obviously false this Els
if this is going to fail as well
because user status is not equal to verified so this is also false and then what's
going to happen is it's going to
go to this else block and then it's going to return this div with this span
that's all you see over here your account is disabled okay now again that
doesn't necessarily mean that the account is disabled it could just mean that in
the system you didn't actually explicitly set the status when you may
have created the user so this is obviously not a good way to you know
handle that situation so what I'll do is I'll write an L if and I'll say user
status equals account disabled and then now I'll just go ahead
and copy this and paste this over here and I'll just say
your account is disabled okay and if the user doesn't
have any status AK if the user status is null or undefined I'll just say please
contact a system admin okay so now you'll see that it says please contact
the system admin because user status is null if I change it to account disabled
it will now say your account is disabled so notice how we're not using a tary
operator in this situation we're using an if else or if else if else statement
right and in this situation it's perfectly fine to use these explicit conditional
statements because in a ter
with with a turn operator you're going to need to actually Nest a bunch of
operands and it's going to make your code look very ugly and I just think it isn't
really ideal and especially if you
use linters such as es lint or prettier sometimes they might have rules sets where
they don't want you to Nest tary
operators so avoid nesting Turner operators if you have to check multiple
values more than two for a condition definitely use an explicit if else if
else statements you can also use a switch case as well and I'll quickly show you
how to use a switch case or
switch statement so what I'll do is I'll use a switch and I'll go ahead and just
comment all this out real quick let's use a switch switch case so user status
will be our condition and then we need to set up our case so we'll do well the
first one we'll do is not
verified and then uh what I'll do is I'll just return and I'll literally just
return
this right over here I may need to you know let me uncommon all this out just so
it's easier for me to copy and paste
all this okay we're just basically converting all this into a
switch now let me go ahead and copy this to handle a case where it is
verified okay and let me remove this then let me go ahead and copy this right
over here and then that's going to be the case for account
disabled and then the default case for switch statement
default just like this okay so this is what it looks like as a switch statement
you have your switch keyword and then you have your condition which is user status
because we're checking the value of user status and then we have four
cases we have case not verified case verified case account disabled and then
the default case which is the equivalent of our else block that we had earlier
okay and then you'll notice that if I were to change the value of user status each
time it's going to go ahead and
pretty much return the corresponding div with its text so current Curr user
status is equal to account disabled so it's going to say your account is disabled
if I change this to
verified it's going to return your verified you can go ahead and play around with
the values and see how it
Handling Events
works but hopefully this all makes
sense in this section of our react tutorial I'm going to teach you how to perform
event handling on your HT ml
elements event handling is a very important thing that you must learn how to do
because majority of the time
whenever you're building out your user interfaces it is very likely that you will
need to handle events and there are
are a lot of different events that you can handle for your HT elements but I'll
cover the most common ones that you will come across such as handling events for
user input in other words whenever you have a user needing to type data into a form
and submitting that to a server
you're going to need to register events for that so what I'll do is I'll create
a new component and I'll call this login form so we'll set up a very basic form
that a user can enter their username and password and then we'll also create a
button that they can click on and we'll pretend like that button is sending data to
a server obviously we don't have a
server to send data 2 but the idea behind this is to show you how to actually
register these event listeners
on these HTML elements so I'm going to call my component login form. jsx or the
file and then we're going to go ahead and
Export a function called login form and then what I'll do is I'll just
return a form okay and what I'll do here is is I'll set up two input Fields I'll
set up one which is going to be for the username and we want to make sure we
associate our input Fields with a label so I'm going to give this input field an
ID called username and then for the label we want to have this HTML 4
attribute and then it's just going to be associated with whatever the ID of
this input is which is user name so we want these to match and then for the label
text we'll just use
username and this should be it let's go ahead and render our login form in our
app component so let's render that and let's make sure that it is appearing on the
screen and it is and when I click on the label itself you'll see that it focuses
on the input field which means that we've Associated this label with the input
field correctly okay
let's go back to our login form and let's do the same thing for the password field
before I do that though let me go
ahead and add a Break Tag after label so that way it is on the next line This
input field so I'll copy this full thing and I'll paste this and then we'll just
change this to password copy that change the ID of this second input field to
password as well then change the text from username to pass password for the second
label and then you can see when I click on it it is properly associated with the
second input field let me also go ahead
and add a Break Tag right over
here and let's see let me also do one more thing I'll go ahead and set
the type of the input to password so that way when I type in here
you'll see that we have the password hidden okay so hopefully this is pretty
straightforward again regular HTML regular HTML form so I can type my
username and I can type my password let's go ahead and set up a
button and we'll just go ahead and give it the text login and let's also make it
on the next line as well there we go all right so now what we want to do is is
whenever we are typing into our input fields we want to be able to detect
whenever the user is typing in these input Fields but we also want to grab the data
that they are typing okay now
again there are a lot of different events that you can handle so if you just go to
this input field this input
element right over here and if you just type on you can scroll through all of these
different events that you can
handle and again some of these events are pretty self-explanatory a lot of these
events would not make sense to
handle on an input field but the most common one that we would want to handle
Input Field onChange Event
is the onchange events now this event is basically going to trigger whenever the
value of the input field is changed hence the name on change now the value that we
want to
pass to this on change event because it expects a value it's going to be a
function that it needs to call and this is typically known as an event
handler so all it really is is just a function and I can just pass in a regular
Anonymous
function inside just as a regular value for this onchange attribute and I can
just write a console log for now so every single time the value of the input
field is changed it's going to go ahead and invoke this function it's going to call
this event handler and you're
probably wondering well what exactly do we mean by value of the input field well
I'll show you so this callback function
this event handler function actually takes in an argument and it's known as
the event object okay to be more specific it's actually a change event
type so I can actually console log this e typically you can name it e or events
you can call it whatever you want but commonly people name it e or events okay
and there are a bunch of properties on this event object and one of them is
actually the Target and the target itself references the actual HTML
element itself you'll see in just a second so what I'll do is I'll go into
the browser right now and let me just refresh the page and and I'm going to go to
the username field because that's the
current element that we have our on change event being uh registered now
whenever I change the value of the input field and the way you do that is literally
just by typing so if I just
type something you'll see that it logs the actual Target so the input field
itself and then you'll see it says value change and every single time I type
something it's going to say value
changed and I can type literally anything I want it's going to keep on calling this
function this event handler
whenever the value changes okay so hopefully that makes sense just to be
more specific this onchange event is not necessarily detecting whenever a user is
typing it's just detecting whenever the value of the input field is being
changed and in order to change that is by typing into the input field so you can
think of it as it is is kind of like
you know detecting whenever a user is typing but I do want to be more specific with
what exactly is going on there are
actual events that you can register that specifically are for detecting whenever
a user press a key so for example there's an Onkey down
event and this event is triggered whenever you
actually press a key so for example I'll just log
e Let me refresh and if I type something if I just press a key you'll see that
right over here on line 13 which is where we have our console log so right now the
on key down is being triggered
and it's calling this function and keep in mind that you can have as many events
registered on a
single element so you can have literally every single event possible being
registered on an element so right now
you can see that the Onkey down event is being triggered and there's actually this
property that you can see called key and this key actually tells you what the
actual key was pressed so if I do e.
key Let me refresh so if I type A you'll see that it logs uh whatever the value
of e. key is which is a if I type B you're going to see says b c you're
going to see it logs C and notice how if I hold shift it literally logs
shift and then if I do shift a you'll see that it logs shift a okay now I'll
go ahead and actually just remove the on key down event handler just so I'm not
confusing you all okay so going back to our on change event the important field
that we want to reference is actually the value of the input field so in order to
actually get the value of the input
field in other words whatever the user is typing we want to reference the value
property on the event. target property
itself so e. Target is an actual object and it has
this value property itself okay and again if you've worked with client sided
JavaScript and just plain HTML Cs and JavaScript this target element is
literally an HTML element instance to be more specific in HTML input element
instance okay so you can see that when I reference Target there are a bunch of
different properties that you might be familiar with okay you can scroll through
all of it so for example if you
wanted to see all of the possible classes that are associated with this
input field to give it certain Styles you could reference e. target class list
and that would give you a list or an array of all of the classes that are on
this input element okay but we want to reference value and now what I'll do is
let me refresh so if I type my username let's just say ansen you'll see that
each time I type it logs five times but you can see that we have ansen at the
fifth time it was logged okay so this tells me that this is what my username
is because we actually want to get what whatever the user last typed okay
whatever the last value is so it's kind of like it incrementally builds up the
username so it goes from a to a an to a ANS to an anso and then an ANS o n okay
so hopefully that makes sense so again if I keep typing um let's just say Anon
the developer the moment I stop this is going to be the last
value that was typed into this username field and if I just went ahead and I
just deleted the whole thing you'll see that the value of the username field is
empty and I can actually just copy and paste stuff in here directly and you'll see
that it just
goes ahead and gives us ANS in the developer as the value itself without
having this whole uh thing being logged okay so this is why I said earlier that
onchange event is not necessarily detecting whenever a user is typing it's
just detecting whenever the input field is being changed and again that can happen
either by typing either by
pasting a value or if you have let's say an image upload system and you can also
just drag and drop stuff into uh the input field which is something which is
something else that we'll talk about possibly in another tutorial but hopefully
this makes sense
okay so let's go ahead and add the onchange event listener to our password
field and it's the same way that we do it for the username field so we'll go down
to our password field so this input
field right over here we'll add the onchange events add a callback function aka the
event handler whoops and remember the event
handler takes one argument the events object and I'll just console
log and I'll use a template string so that way I can have a formatted uh display so
password and then e. target. value and I'll do the same thing for username so
that way we have a more formatted text so e. targets.
value okay this is a template string right over here
so now what I'll do is I'll refresh and I'll just type anen the dev and for my
password we'll just type password and
now you can see that right over here I type an the dev
so it logged uh literally let's see a total of I believe 11 times so 1 2 3 4 5
6 7 8 9 10 11 so it called the onchange event handler 11 times for the username
field okay we didn't do anything else for that input field after and then we
went ahead and typed uh a total of eight characters in the password field so it
called the on change event eight times okay now if I were to click the login
button what would happen is we would want to submit whatever the latest
values for our form Fields so for example the latest value for for the
username field is anen to Dev and the latest value for the password field is
just password so these are the values that we would want to send to the server
because that's what the user last inputed now there are many ways that you can
handle form submission on the front
end side so right now we currently have just a very basic form with two input
fields and then we have a button inside our form now one thing that I want to show
you that you should definitely know
is there is a default behavior that the browser will do okay so you can see
right over here if I actually just click on this login button you'll see that it
looks like the browser is refreshing
okay you can see over here that this refresh icon is going from the refresh icon to
the X icon so it looks like the page is refreshing so if I if I were to type
something in the username field if I
click login notice how when I click log in the page refreshes and then the field
is all cleared out so this is the default behavior of the browser you can actually
prevent this and I'll show you
how to do that but the default behavior of a form what happens is this so there
are actually two attributes there is this method attribute and typically you set
this to either get or post it
depends on what you're trying to do typically if you're logging in or if you're
creating data on the server side
in other words let's say if you're uh creating a blog post you would want this
method to be post okay so that is
specifying the HTTP method that you are using and then there is this action
attribute which is going to be the path that you're sending the data to okay so
this would literally just be something like SL API login and if I actually go
to the network tab right now and let me just filter by fetch
you'll see that whoops okay so ignore this ignore the network tab just look
right over here when I clicked on uh the button you'll see that it says this Local
Host page can't be found uh and
you'll notice that the the route actually got updated to SL API loged in
so it tried to actually uh make a request to this path on the same domain
on Local Host Port 5173 API login we don't have that path
so that's the reason why we're getting a 404 uh error and that's okay but I just
wanted to show you what happens by default when you click on the login button now
what I'm going to do is I'm
going to show you how to prevent this default behavior from happening because
actually nowadays you don't actually
want to submit data this way using the method and action attribute because what
happens is the whole page just refreshes and then you might lose uh some action
from happening on the page we want to do
things asynchronously in other words we want to just send the data to the server
without having to refresh the page
entirely because there might be something going on that we're waiting for to happen
on the page that we don't
want to necessarily cancel okay so I'm going to remove these two and what I'm
Form onSubmit Event
going to do is I'm going to handle an event called onsubmit okay and again this is
just a
regular event that takes in a callback function and then it's also going to take in
this event object as well again
every single event handle will have this event object that you can optionally pass
as an argument if you need it but
what I want to do is I want to reference this event object and then there's this
method called prevent default okay and I
want to show you what happens now if I were to click on the login button notice
how now when I click on the login button the page does not refresh anymore if if I
type into my form Fields And if I
click log in you'll see that the page doesn't refresh and our form fields are
not cleared out okay I mean they were being cleared out because the page was
refreshing but you can see that it's not
refreshing the page anymore okay let me fix the path real
quick no more it's not being refreshed anymore but if I remove this prevent
default you'll see that it is now refreshing so what did prevent default
method does is it literally just prevents the default behavior of the browser so
remember what I said earlier
is the browser will have its own default behavior that it will do for events and
there are a bunch of different default behaviors that the browser will resort to
and you can always override this by
literally just calling this method because sometimes you might not want to have the
browser's default Behavior
occurring you want to handle your own actions for your event and we'll explore
them as we handle different events okay so what I want to do in this event is
first I want to prevent the page from reloading and then what I want to do is I
want to get the latest values that
were uh typed into the input field so to achieve this what we're going to do
first is let me actually go to my input fields and there was actually this was
something that I should have done earlier I want to associate the input field with
a name so you typically want
to give a unique name for your input Fields so for example for username I'm just
going to give it the name username
and then for password I'm going to give it the name password okay so that way the
actual
form element knows the name of these input Fields okay now what I'm going to
do is I need to actually get a reference to the form element itself and we can do
that by referencing this event object for the uh event handler that we used
for onsubmit so if I reference e. Target inside this onsubmit event handler
function this would actually get me the HTML form element instance which is the
actual form element itself now what we're going to use the form element for
is we're actually going to pass it as a value to a form data class construct
structor so form data is actually a class that you can use that will actually allow
you to retrieve values
from the form element itself so the way that we can do that is first we'll declare
a variable called form data just
like this and then we'll create an instance of the form data class so equals new
and then form data and this
is again built into the browser API and then we'll pass in the HTML form
Elements which is going to be e. Target and now what I can do is I'll
console log form data and let's just see what it looks like when we log this form
data instance so if I click log in you'll see that current it looks like
it's an empty object but I believe it's because it's not properly serialized but
what I can do here is I can actually reference form data and I can reference get
and then I can pass in the name
of the input field that I want to retrieve the value for so for example if I wanted
to get the data for our
username input field well I'm just going to pass in username just like this okay
and remember it needs to match this name value so for example remember how
earlier I added the name attribute for my input fields and the value of name
for the username and field is just username so that is what we need to pass
in so if I refresh if I click log in you'll see
right now it is logging the value of username if I type
ansen you'll see that when I click the login button it is logging ansen which
is the value that was retrieved from the form data doget function call and it's
literally just getting that data from the form data object itself and notice how if
I remove this name add attribute
from the input field it's just going to return null so you need the name attribute
in order for this to work now
obviously um this is only one of many ways that you can use to handle a
retrieving form data later on when we get to actually managing State and
you'll learn how to bind your input fields to State variables so you won't
actually need to do it this way okay but this is one way that you can use to
actually get the form data itself okay
so similarly if you wanted to get the the value for the password input field
well you would literally just reference form data and then call the doget method so
doing the same exact thing that we
did for username we just do it for password so form data. getet and then we pass in
password which is the
value that we set for the name attribute for the the password input field okay so
just again if if the name value was password 1 2 3 then the value that you
would pass over here is password 1 23 just like that and now if I type
something for password it'll see now it's going to log that value on line 8
or password okay so let's go ahead and do this let me
assign this to a variable so form data. getet
username and then we'll do the same thing for password let me just change this back
to password instead of password 1 2
3 and then cons password equals form data.
password and now what I'll do is I'll just pretend like I want to submit this
to some server right so you might make some API call so for example there a
built-in fetch API that is part of the browser and you can use this to submit
data to a server so you can pass in some URL and again some of you may not know how
to do this quite yet because you
haven't worked with backing stuff don't worry we'll get to that later on but just
as a preview you would pass in a
URL to the server so let's just pretend it's Local Host Port 3001 and then you
would pass in your
data just like this and then username name then password something like this
okay and then you for fetch you also need to set the method and typically we want
to set it to post for logging in
okay so this is what a potential API request could look like where you attach the
username and password in the request
body then you pass in the method type which is going to be post and yeah and
then of course you would just wait for a response from the server and then you
would handle that accordingly so if the
user successfully logs in you may want to redirect them to their dashboard page
so hopefully all of this stuff makes sense when it comes to registering events for
your HTML elements now there
Registering Window Events
are other events that you may want to register not on a specific element but
sometimes on the entire page itself that the user on so a good example of this is
let's say you want to detect whenever the user is scrolling or if the browser size
the window size has changed so in
that situation you may want to actually use the global window object and then
use this add event listener method which some of you may be familiar with this if
you have learned how to register events
dynamically using plain JavaScript for your HTM elements so window. addevent
listener and then there is this resize event and then we'll pass in The
Listener function just like this and then I can just literally log e
doin there should be uh screen I believe screen X I believe is
the property let me zoom out a little bit
and let me open up the browser tools so if I resize this you'll see that every
single time I change the size of the
viewport it goes ahead and logs uh this object over here this window
object uh let's see actually I believe it's not e we want to log window. screen
X and then window. screen y okay and then now let's refresh and if
I resize you'll see that every single time I'm sorry this is actually the
position inner height and inner width is what I want so sorry about that okay so
notice how every single
time I resize the page the height is obviously the same but the width is
getting smaller and smaller okay you can see the current page size is 682 by
1359 and that is being logged over here of course if I uh were to
change the height you'll see that that is going to be logged over here 699 by
509 or the other way around okay so that is how you can detect whenever the size of
the page is being
changed so you might want to do this if you want to handle certain Dynamic um
viewports using JavaScript but a lot of times whenever you're handling responsive
design you want to do that
with CSS but there might be situations where you need to do that with JavaScript
and that's how you could do
it using the resize events okay now typically you don't want to do it like
this you'd want to actually wrap this in a use effect hook I'm not going to show
you that right now because we haven't
gone to hooks yet but later on when you actually learn about hooks I'll show you
another example on how to properly
handle those events with hooks okay so just wanted to show you a quick example
hopefully this all makes sense and I'll
see you in the next
State
section in this section of our react tutorial I'm going to teach you about States
state is literally just a representation of data that can change over time we use
state to represent data that is stored in a component you can think of State
like a variable it holds your data but instead state is actually just an
internal object for the component that is managed by react and react actually
gives you the necessary tools to create new state values and manage them
stay is necessary because it enables our components to store data that can be
used later or updated imagine you're creating a card game let's say Blackjack
and you want to keep track of the number of cards dealt in every player's hand you
know that such information will
change as the number of cards dealt will increase as the game progresses and the
player's hand will change after each turn so you would need to track all of
this information and to do this we would need State now you don't always need State
all the components that we've created so far have no State I'll show you some
examples now of how we can create some
stateful components now what I'll do is I'll actually create a form in the previous
example I actually created a login form with two input Fields but I actually
didn't use any state at all we were able to track the username and password using
the form data API but instead what I'm going to do is I'm going to Define some
State and I'm going to show you how to
bind the state values or the state variables to our input fields and this is
actually known as data binding and
it's a a very important topic to understand and it's usually what you would want to
do to create forms instead
of just grabbing it from the form data API so what I'll do is I'll create a new
file inside my components folder and I'll call this register form so this
will just be a form where we will have the user enter in their new account details
so if they want to create an
account they'll create it through this form so let's do this export function
register form and we're going to return a form and I'm just going to Simply
create a couple of input Fields uh and what I'll do is this I'll wrap every
single input field in a div I'll also make sure I associate it with a label so
let me give this ID I'll do uh this let's do username and we want to make
sure we associate this label with the correct input field so I'm going to pass the
ID that I assigned to this input
field as the value for HTML 4 for this label
oops okay and then I'm just going to copy and paste this twice
and then we'll do password
password and then I'll just do uh display name I'm not going to do a confirm
password you can you can do
whatever you want to and then I'll just do display name just like this let me go
ahead and
make sure I render this register form I'm going to remove the login form
render in the app component and I want to render the register form instead just so
we we don't confuse everything I'm
going to remove the import and let's go to our application now so I have my form
displayed in the document that's great now let's go ahead and Define some state
for each one of our form field so basically what I want to do is I want to create
some State variables or some
State values that will represent my username my password and my display name
so whenever I am typing in the username form field I want want to update the
state value for the username for the password as well as the display name
this will give me full control of each value and I can do whatever I want with it I
can send it to an API I can display
it to the user in real time as they are typing whatever it is now in order for
us to create some State we need to use a function and that function is called use
State and we can import this function from the react package so we're just
useState Hook
going to import use State like this from react
okay so import you state inside the pair of curly braces because it's a named
import and then from react just like this now one thing that I also want to
mention is that Ed state is also a react hook react hooks are something that we
have not yet talked about but don't worry and in a separate section of this react
tutorial we will formally
introduce to you all react hooks remember that react hooks are also just
functions okay so react Hooks and functions are
synonymous so this use state is a function it's also a react hook and we
want to invoke this function because just importing itself is not going to do
anything we need to invoke this function
in order to do something so whenever you want to create state you use the used
State hook or the Ed State
function you call it and this used State function will always return an array
with two elements okay I'm going to go ahead and conso log UST state right now
before I do anything else and I want to show you in the document what this looks
like so right now you can see that when
I log U States or the the invocation of UST state so I'm calling UST State and
I'm logging the value that's returned you can see that it's an array and there
are only two elements the first element is undefined and the second element is a
function
okay so what the first element is is actually going to be the value of your
default state so so far we actually didn't pass in anything into this use
State function call so you can actually pass in an initial State and for example
if I wanted to pass in an empty string I could if I wanted to pass in hello world
I could and then you'll see that when you log it the array now has the first
element is a string hello world and the second element is a function okay so you
can also pass in a numeric value so you can pass in one and then you'll see that it
logs one you can pass in a a Bine and
it will log true you can pass in an object and then it'll log that object
right over here okay so I just want to show you how this works you can pass in
literally anything you want in our
example we obviously want to make sure we're passing an empty string or just a
string in general because we're working
with text in our form Fields so it makes sense for us to have a empty string as a
default value otherwise it will just be undefined by default okay now the other
thing that I want to mention is this function so before I mention that function let
me go ahead and show you
the proper syntax of how to actually create States so you do call this UST
State function and remember that it returns an array now you can actually
reference that array in many different ways so for example I can just I can just
assign the return value of U state
to a regular variable just like this okay and if I wanted to I can just
reference each element by referencing the index so result at subscript zero
and result at subscript one okay now obviously this is not the correct approach I
mean you can do this it's not
wrong but I'm going to show you the right way to do this okay because I know some
people might think about oh can I
just access like this yes you can but you shouldn't okay so remember that the
first value in the array that is returned from you state will always be
your state value okay by default it will be whatever you pass in to UST State as
an argument and then the second element is going to be your function this
function is a very special function it's called A dispatch function some people
call it a Setter function or an updater
function all correct terms but it's resp responsibility is to update your state
variable okay remember how earlier I said react gives you the necessary tools to
manage your state and that entails
creating your state updating your state etc etc well this is how we can manage our
state so what I want to do is I want
to use array destructuring and the way that it looks like is this I'm going to go
ahead and have my const keyword and then after con I'm going to have my square
bracket and then inside the square
bracket I'm basically unpacking the elements from the array and then I'm giving it
a name at
the same time so it looks like this I'm going to call the first element username
and then the second element is my function and I'm going to call it set username
just like this okay if you
haven't worked with array destructuring before this might look a little bit weird
but all you need to know is that
remember you state returns an array and all I'm doing is I am just taking the
values from each index each position of
that array and I am giving it a name so for example the first value is going to
be username and I'm calling that value username the second value is my function
my updator function and I'm giving it a name called set username okay you
typically want to call your function your updator function uh um set and then
the name of your state variable okay so username and then the function is going to
be called set username okay we're
going to do the same thing for password and display name so go ahead and do the
same thing for the next two so we're
going to do const password and then my Setter function or my updator function
is going to be called set password and then I'm going to call the use State
variable or I'm sorry UST
State function I'm going to pass it a default value of an empty string I'll do the
same thing for display name and I'll
call the state variable display name and then the setter function will be called
set display name just like this so right now I have created a total of three
state variables and each state variable has its own updator function okay for
the rest of this video I'm going to call this function a dispatcher function okay
cuz that's the formal term because if you hover over this it actually uh says that
the type is a dispatch function
okay so now what I'm going to do is I'm going to go ahead and take each state
Binding State to Input Fields
variable and I'm going to bind it to my input fields and the way that we can do
that is like this so remember that the input field actually has an attribute called
value so what I can do is I can
say okay well I want to associate the value of the input field with the value
of my state so for username I'm going to associate username uh or I'm going to
associate
the username input field uh with the username States just like this I'm going
to do the same thing for the password so value equals password just like that and
then display name we're going to do the same thing now right now if I go to my
form if I try to type right now I'm typing right now and you'll notice
that nothing is actually appearing in the text box I can't see what I'm typing okay
and you'll also notice that we have
a warning and it's saying that you provided a value to a form field without an
onchange Handler so the reason why we
cannot see what we're typing is because we also need to make sure that since we are
binding our state variables to uh an
input field we need to make sure that as we are typing we are using an onchange
event handler to update the state
otherwise it's never going to update at all okay so I'm going to go through each
input field and I'm going to use the
onchange hander and remember that in the previous section we did learn how to use
event
handling and we did use the onchange Handler remember that whenever you type
or whenever you copy and paste something into that input field basically whenever
the value of the input field changes
this event is triggered so what I can do is I can pass a callback function and that
callback
function takes in one argument which has the event object okay and remember that
event object has the target object which
has the value and this value is basically going to have what you type or
paste into the input field so what I want to do is I want to actually update
the state value of username whenever the value of the input field changes so
remember what what I said in order to update your state value you need to use your
dispatcher function in our case we
have our set username function so we're going to call
that okay and then we're going to set the new username value with
whatever the e. target. value is okay so
in other words whatever it is that I am typing or pasting into the input field
is going to be passed as an argument to the set username dispatch function and
this will basically uh perform an update to the username State variable okay so
now you'll notice that if I actually begin typing you'll see that now I can
actually type into the username box okay but obviously you don't really visually
see anything that's going on so here's what I'll do I'm going to go ahead and
render this username State variable to
the document just so you can see it changing in real time as I am typing so
what I'll do is right down below I'll just go ahead and create a div and I'll
just say this uh
username and then I'll evaluate the username like
this so now watch this as I am typing you'll see that that each time I am
updating the states of my username variable it actually is reflective on
the document itself and that's because I am updating the state by calling the set
username function okay now of course if I removed this on change event handler
and if I refresh you'll notice that as I'm typing nothing is happening nothing
is being displayed to the document because we're not updating the username State at
all okay hopefully this makes
sense let's go ahead and do the same thing for the password field and the display
name field so again this is how
you're always going to want to create your forms in react okay we're going to
have our onchange Handler and basically we're going to pass in that callback
function that callback function will
have one argument the event object and then since we are um binding the
password uh State variable to the input field right over here we want to make sure
that we are calling set password whenever we are changing the value of this
password input field so I'll call
set password and then pass an e. target. Val and then I'll do the same thing for
display name so on change and I can actually do this shorthand I don't need
the curly braces like this for this function I can just do set whoops let me
fix this I I can do set display name e. Target value just like that okay just
like that so let me remove the curly brace real quick I do this up a little
bit there you go so now what I'll do down over here is let me just go ahead
and copy and paste this a few more times and show
you the values being changed in real time
okay so let's evaluate each state variable so if I go back to the document
you'll see now the warnings all disappear because we have appropriately uh
registered an onchange event handler
to each form field since we binded the value to each input field so if I type
something for username type something for password type something for display name
you can see that it is being
updated every single time I change the value of the username password and this
play name field and it is being rendered to the document okay now you're probably
wondering well how does this form
example differ from our login form example right because in our login form example
we had no State at all but we
were still able to access the username and the password via
the form data API now the major difference here is that in our login form we don't
have any state and we're
getting the information from the the form data API and you'll notice that the only
way that we're able to grab this
data is whenever we actually trigger the onsubmit function or I'm sorry whenever
the onsubmit event is being triggered and then it calls this callback function over
here and then we create an instance
of form data and we pass in the Target which is going to be the form element itself
and that's how we can grab the
user and password now here's the thing though right I could actually move move
uh this form data instance up a layer so I can actually move this up top over
here okay but if I move this up top over here so before the
return I don't have access to the actual form element itself okay so I can't just
grab the information like that so the only way for me to get the username and
the password is by clicking on the submit button and sometimes we don't want to do
that
because clicking on the submit button means that you are going to submit the data
to the
API but perhaps you're not ready to send that data to the server just yet you
want to perform some kind of validation in real time to give the user feedback so
they can make changes to what it is
that they entered in the input field okay in this login form example there's no way
for us to access the data via
State the only way that we can do it is from the actual form uh element itself
okay and this is not necessarily good in this register form example I can
literally grab the username field whenever I want okay so for
example you can see that like I said we binded the username variable to this input
field and then every single time
the value changes we are calling the set username function which updates the value
of username so whenever this field
is updated I can always rely on react to update the value of the username field
and and I can get the latest updated value of username okay in the login form
example we can't get the username without clicking on the submit button so this
allows me to do a lot of different
things like for example um I'll I'll show you an example right let's go ahead
and create a button uh and let's call this sign up okay let's say for example I
only want
this sign up button to be enabled if all three form fields are filled out okay
how do we do that well remember now that we have state what I can do is I can
write some logic I can write a conditional to check to see if username
password and display name Are all uh filled out in other words um they all
have a link greater than one or they're just all non-empty string so what I'll
do is I'll create a variable and I'll call this is disabled so this variable
is going to represent whether the button sign up will be disabled or not okay so
remember that if at least one of these form fields are not filled out then we
want the button to be disabled that means the user must fill every single form
field in order for the sign up
button to be enabled so what I can do is I can just basically uh do this remember
that an
empty string is a falsy value so I can just use a negation operator so if not
username or not password or not display name so
basically if username is a falsy value so if it's an empty string and then we
negate that
which evaluates to true that will basically mean is disabled will be true this
whole statement will evaluate to
true because remember with the conditional or if at least one of these conditions
are true the entire
conditional statement is true okay so if at least one of these evaluates true then
is disabled will be true and then
what I'll do now is I will go to the button and I'll use the disabled
attributes and then I'll set it to the value of is
disabled okay so now what I'll do is I'll go back to the document and
you'll see now the sign up button is disabled but notice how if I type one thing
into username if I type one thing
into password but if I leave display name alone sign up is still disabled but the
moment I type something to display
name you can see that in real time the sign up button is now enabled if I
delete a uh something from the password field like if I clear the entire password
field okay so what happens is I remove the letter A from the password field
making that password field empty right and since I updated the value of the
password field set password was called okay the password State variable is now
empty again which Updates this conditional statement over here
okay since password is empty so remember password is a falsy value now not falsy
which evaluates a true makes this is disabled variable true which means that
the button will be disabled okay if I type something in password again sign up
is now enabled so me having State enables me to create Dynamic buttons
like this where I can enable it and disable it based on certain conditions that
occur whenever I am updating either
something in the input field or perhaps something changes in our component so
hopefully this example makes sense so
now in this example I'm going to show you how we can create one single object that
has our username password and
display name all set as fields and instead of just having three different
individual State variables that we need
to update will update the object and the specific field that we need to update so
what I'll do do is I'm going to delete everything over here and I'll create a
state variable I'm going to call it form fields and then the dispatch function will
be called set form Fields we'll
call use State this time we're going to pass an object okay we're going to set
the object to have our username field which will be an empty string so this is
going to be equivalent to having those
three state variables just in the form of one single object so we'll have
password initial value will be an empty string and then display name same thing
we'll go ahead and update all the references to username instead of username it's
going to be form fields.
username because remember form Fields is now an object and we can access the
username property on form Fields same
thing with the password so form fields. password and then form fields. display
name we'll do the same thing down over here where we rendering the data and I'm
going to temporarily just comment out the button it's not really important right
now okay so now we have our
initial values set for our username password and display name inside this single
object if I were to console log
form fields and let me go ahead and just do
this let me remove all of the original dispatch function that we were
calling just so we can actually go to our browser tools so let me refresh the page
you can see right now
when I render the states when I render form fields we have an object that has
all three of our values all set to an empty string and that's perfectly fine
now when it comes to updating the state this time it's done a little bit
differently because we're no longer updating a string we're updating an
object so there is a couple things to keep in mind when you are updating something
like an object when you're
updating an object you need to pay attention to what exactly it is that you want to
update so for example for my
input field for username I want to make sure that I am updating the username and
the username only I don't want to update
the password or the display name whenever I'm typing stuff into the username box it
wouldn't make sense so
we need to be careful when we update the state so this time in our onchange event
handler we're going to call set form
fields and remember at form Fields is going to update form fields which is an
object so in order for us to update our object successfully without touching any
of the other properties the way that we want to do it is like this instead of
passing an object which you might guess
we might pass an object and then set the username to e. target. value okay you
might guess that this is
the right approach but it is not because right now by doing it this way yes you are
updating the username but what
you're doing is you are overriding the entire form Fields object okay so the
way this would look like is you'll have the username updated but password and
display name will be empty okay if you
don't believe me I'll show you right now if I refresh the page I'm going to type
something into username notice how now
notice how now username this is uh the username is the only field that EX exists in
the form Fields object
password and display name no longer exist as properties because the object that we
passed to set form Fields is the
entire literal object that we are updating form Fields with okay and you can even
see that we get a warning it
says a component is changing a controlled input to be uncontrolled okay and we no
longer have
form Fields password defined or form Fields display name defined that's why this
warning is popping up so the
correct approach to updating an object that you have as a state variable
is like this inside our dispatch function we can actually pass in a callback
function and this callback
function takes in an argument and this argument is actually a copy of the
current state itself which actually I shouldn't call it previous I'm going to call
it current states
okay so this current state is literally just whatever form Fields is so you can
see I can reference the username password and display name just like just like a
regular object because that's
literally what form Fields is now what I want to do and this is how you update
State and react and this will look very similar to any other framework or library
that you may use is you want to
basically create a copy of the current states so you want to take all of the
values in the form Fields object and the way we're going to create a copy of the
current state value is we're going to use the spreader operator on the current
state object so I'm going to go ahead and return a new object
inside this call function over here so I'm going to use a pair of parentheses that
will wrap this pair of curly brace
and this is a short hand notation for us to return an object and then all I'm going
to do is just use the spread
operator on the current state current state object some of you might be
wondering well couldn't I actually just do it on the form Fields object itself
you don't want to do this because form Fields itself is the actual
State and you never want to actually modify the state itself okay react has
this immutable pattern where you want to never actually directly mutate data you
want to do things in an immutable way and the other problem with with actually
using form Fields is that you might not
actually have the updated state for form Fields because the thing with updating
state is that it is not guaranteed to be synchronous okay so you always want to
make sure that you use this callback
function and reference current States because this will give you the actual value
of the current state itself
so we're going to use the spreader operator on the current state object and what
this will do is this will take all
of the current key value pairs in the current state object and then unpack it
into this new object over here that is wrapped in between these curly braces so
basically if there is a current password if there is a current display name if
there's a current username it's going to
go ahead and put place it all inside this new object and then what we're
going to do is we're going to just override the username field which is the field
that we're updating
after we spread the current state object itself okay so then over here what we're
going to do is we're going to reference e. target. valal just like this so what
this essentially does is it creates a copy of the current state object and
then you have a copy of all of the key value pairs of current state and then
you override the username field with whatever the e. target. Val is okay so
this will basically preserve the password field and the value as well as the
display name field and value but
since we are adding this extra line over here setting the username field explicitly
it's going to override the
username field so in a nutshell you're basically creating a copy of the current
state but only updating the username field so that way you preserve the password
and the display name
hopefully this makes sense okay so what I'm going to do is I'm going to copy
this and I'm going to paste it for the onchange for password but instead and
you may have guessed this instead of username instead of a manually setting the
username we're going to manually set
the password because remember when we update the password when we type stuff into
the password field we want to
preserve the username the display name but for the password we want to update the
password with whatever the user
whatever the user currently typed and the same goes for the display name field as
well okay we want to preserve the
username we want to preserve the password but for display name we want to make sure
we update that display name
with whatever we type into the display name field okay so now watch what
happens I'm going to refresh the page and if I type for the username you can see
right over here that it is updating
the form Fields object every single time it's specifically targeting the username
field okay and then I'm going to type something in password I'm going to type hello
notice how it is updating the
password field and it is preserving the username and the value of username which
is Anson so let me go ahead and remove this uh spreader operator on the current
state I'm just going to remove this entirely and now I want to show you what
happens when I update the username so
that works just fine but when I update the password you'll see that
password is just being updated just fine but because we are not using the
spreader operator on the current state to create a copy of the entire State
itself we're not preserving the username or the display name and the object itself
is only containing the password
field so we do end up getting the same warning that we got earlier okay so it is
very important to make sure that you
use the spreader operator on the current state itself to create a copy of it and
then specifically Target the field that you want to update so hopefully this makes
State with Arrays
sense in this section of our react tutorial we're going to continue with state but
I'm going to show you how we
can actually Define state for an array because a lot of times you're going to want
to render
lists of elements such as an array of users and then you may need to make updates
to a specific element in that
array and have it reflect on the application itself on the user's view so
this is a very important concept so you definitely want to make sure you pay
attention to this so what we're going to
do is we're going to create some state so I'm going to have an array of users
so I'm going to call my state variable users and then the dispatch function will be
called set users and then I'm
going to go ahead and call the UST State hook and I'll pass in an array and I'm
going to just keep this simple so I will pass in two objects both will be
representing
users and one thing that I do want to also mention as well is that I have this user
details component I created this
very early on into our tutorial if you haven't been following along then you can
either just create your own custom
user details component or you can just copy this one uh this one is very simple
there isn't any complex logic at all is just rendering plain text okay it takes
in one single prop so we're just going to reuse this component just to save some
time okay so we're going to make
sure that each one of our users have an ID a username and an email address just to
stay consistent with our user details
prop so let's make sure we have an ID a
username and then an email address address and then I'll go ahead and copy
this object and paste it so I have two now and I'll just make sure I change the ID
let me change the username as well as
the email address now let's go ahead and render our users to the
document and we should know how to do this this is known as Dynamic rendering
or rendering lists which we've covered in previous sections of our react tutorial
so we're going to use a pair of
curly braces because we're going to be evaluating some JavaScript we're going to
reference our user array and we're
going to call the map function this function takes in a
callback function also known as a transformation function and it takes in
up to three arguments but we only need the first one and the first argument is just
going to be the actual element
itself that is inside the array that we are currently processing in other words
we are currently transforming this user object into jsx something that is
renderable so we're going to go ahead and have our callback function return jsx
which is just going to be our user
details component we need to make sure we import user details so let's go up
over here and import that from the components folder user
details file just like that now let's go ahead and make sure we pass in our props
so the first one that we must pass in is the key remember that every single time
you are rendering lists of objects or
elements you always need a key associated with it so in this case I'm
going to use the user ID as the key and then now what I'm going to do is
I'm going to pass in the user prop just like that and for the user
props value it's just literally going to be the object user itself okay and there
shouldn't be any issues because we have the same key value payers ID username and
email address so now if I go into
the document you can see now I have both of my users being rendered to our page
now this is wonderful but what if I want it to make updates to my users State
variable so let's say down the road you want to add the option for your
administrator to create a new user on the spot so you may have have a form
that allows uh the admin to add a new user and then it will be updated on this
view so you'll now see three users instead of two or perhaps you want to
update uh a specific users's username such as anen or maybe you want to update
their email address such as anen gmail.com and then you also want to make sure that
those changes are saved and
reflected onto the document or maybe you may want to also just delete the user
entirely so these are all things that I'm going to cover so what I'm going to do is
I'm
going to go into my user details component and I'm going to go ahead and
modify this component just a little bit just so that way we can suit our example
so what we want to do is we want to give the user in this case ourselves the
ability to edit each individual user to whatever it is that they want edited to
okay in order for us to do this we obviously need some kind of text box for us to
type stuff so we need an input
field so this is going to combine all the things that we've learned so far such as
conditional rendering handling
forms handling events things like that okay and again if you haven't been following
along with all of the previous
sections up until now don't worry I'll do my best to explain every single thing
that's going on as well so what what
I'll do is the first thing that I want to do is I want to create some states I
basically want to represent whether or not we are currently editing our user or
not so we're going to go ahead and create a variable a state variable we're going
to call this is editing so that's
going to be the name of the variable and then the dispatch function will be called
set is
editing and then use state so the value of this will be a Bo or the type of this
variable will be a boine and the default value will be false because by default
we're not going to be in edit mode okay
we're going to just be in regular View mode so now what I'm going to do is this
for each user I also want to make sure I display an edit button that will allow
me to change the state of the is editing variable so this will allow me to actually
uh click on the button and then
dis playay all of the input fields in order for us to make updates to our users so
the way that I'm going to do
this is let's see I think what I'll do is I think on the top of every user
I'll just have an edit button so I'm going to go and just copy this
div and create another div that I will just paste this whole thing inside and then
up top over here or actually maybe
on the bottom I I will do another div and I'll add a couple of buttons so the
first one I'll do is edit so it'll look like this okay um if you want to get
fancy you can also style this as well you can use like a flex box but again I'm not
going to make this overly
complicated you know let me actually move this up to the top just so that way this
one pertains to this one okay I
will also add another Button as well I'll add the delete button
because later on I will show you how we can delete the user as well okay so the
first thing that we want to do is whenever we click on this edit button we want to
be able to toggle the state of
is editing okay because when we click on the edit button we want to change our view
from just regular view to actual
edit mode so we need to register and onclick event listener onto this edit
button and we just want to make sure we pass in our callback function like that
this is known as an event an event handler and all we're really doing here is just
calling set is editing and then
passing in uh true but here's the thing though if I only click on this button this
will
always set is editing to true I want to actually toggle this so I don't actually
want to set it to true I want to set it
to um the opposite value of whatever the current state of is editing is so in other
words if if is editing is
currently false we want to set it to true if is editing is currently true we want
to set it to false the best way to
do this is by passing in this callback function and then remember this callback
function actually takes in an argument
which gives you the current state so this is the current state of is editing
and then we can actually just do use a negation operator current state okay I
actually
uh showed you this example when we covered uh the register form example
where we instead of actually passing in a literal value you can pass in a callback
function because that callback
function gives you access to the current state and you can actually return the
new value for the state itself okay so what this will allow us to do is ensure that
we are receiving the actual value
of is editing and then just negating it so that way it is being toggled on and off
okay so now what I want to do is this just very quickly I'll console log is
editing just so you can see that it is in fact toggling so you can see now it
goes from true false true false true false just like that perfect okay so
what we want to do now is I want to conditionally render a form field
whenever we are in editing mode so we know how to do conditional rendering so
that shouldn't be any surprise so the only two things that I want to be able to
edit or give the user the opportunity
to edit is their username and their email address we don't want to allow them to
edit their ID so what I'll do is for the username
field right over here I'm going to go ahead and edit this right over here so
I'm going to use a tary operator so is editing so if we are in edit mode then
we will display an input field otherwise we will display just their username now I
will make some
changes to this input field in just a second I just want to show you how this will
look like so if I refresh the page
you can see right now we're currently in View mode okay if I click on the edit
button it's going to take us to edit
mode okay so that should be pretty straightforward we were're previously in
View mode now we're in edit mode okay so let's go ahead and do the same thing for
email address because we also want to just allow the user to edit their email
address as well so let's do
that is editing input or email okay if I click
edit now you can see that we have our username field and our email field if I
click this edit button down over here it will reflect on this user
itself okay so hopefully this makes
sense now let's go ahead and go back to our input fields we want to make sure that
we have the correct attributes set
so first for the username field let me set the name to username and then let me
give this an ID
of username as well uh and then let me go ahead and
also set the value so we actually want to bind a state variable to to this
input field so that way we can actually track the state of whatever the user is
typing into this input field so we do need to create a state variable for the
username so I'm going to do that right
up top over here so cons username and then the dispatch function will be called set
username and then we call use
State Now the default value you might be wondering well I'm going to pass in an
empty string right well you could but
actually something better that might be more appropriate is we can actually pass in
the users username and set that to be
the default value and the reason why this would make sense is because first of all
it would give a better experience
for the user because think of it like this right when you've used the form before
let me zoom out a little bit when
you've used the form before and let's say you have tried to edit your own username
when you click on the edit
button you'll see this input field but then you'll also see your current username
as well and not every single
application does it this way but I personally think that it's better from a user
experience standpoint so we're
going to go ahead and do that so let's go ahead and pass the username as a
value for this value attributes and then we need to make sure that we are adding
an event handler for our input field whenever we are changing the value of
the input field so that's going to be the onchange event handler and again I also
covered this in the previous
section when we talked about the register form so go ahead and check that part out
if you haven't already so just
remember that whenever we change the value of an input field in other words if I
were to type something or paste
something inside the input field it is going to trigger this onchange event so it's
kind of like it is detecting
whenever you are typing something but it doesn't necessarily mean that it is
detecting keyboard
Strokes just want it to be uh specific so we're going to pass in our event
handle function remember that this function takes in the argument the event
object itself and then what I'm going to do is every single time this function is
called we
want to update the state of username and to do that we just call set username and
then we can pass in e. target. value okay now since the default value is just
going to be username which is this state variable right over here and the default
value of our username State variable is going to be whatever it was that was passed
in uh as this user prop that
means that whenever you are calling set username it'll basically just be
whatever the user is either deleting or adding onto their current username
unless if they just control xit in other words they just cut the entire input box
and just paste it in something new okay
so if I refresh you can see now if I click edit you'll see I have my username
and then you can see that my current username is just right over here and I can
type and I can change whatever I
want okay so hopefully that makes sense we'll do the same thing for email so
we'll go ahead and I'll just duplicate this line we'll change this from user.
username to user. email and I'll change
up the name of this from email uh to set email or I'm sorry from
username to email and then from set username to set email and then now let's go
down over
here to our input field for the email and and we we'll just do the same exact
thing I'm going to copy all these attributes and just paste them over here and
we're going to set the name to email
set the ID to email and one thing that you could also do with uh email Fields is
you can actually set the type to
email so that way this ensures that the user is actually entering an email okay but
I'm just going to leave this alone
for now I'm not going to do that we're going to bind the email State
variable to this input field and then instead of just calling set username we're
going to call set
email okay so now if I click on edit you'll see that I have both my username
and email Fields being displayed and it has the current status of our username
and email inside the input boxes itself okay so now what we want to do is
I want to be able to make changes to my username by typing into these fields and
then I also want to make sure that I can click on a button to save these changes
and then when I click on that button
what needss to happen is we need to update that specific user object okay so
there's a lot of other things that we have to do so we're going to take it step by
step the first thing that we want to do is obviously have our save
button so I think what I'll do is I think up top over here I'll just add a save
button again this is not the most
uh Pleasant viewing experience but again the whole purpose of this is to show you
functionality over styling and looks
okay you can worry about styling this up yourself later on but I just want to
really just focus on
functionality so we're going to add this save button right over here and then when
we click on the save button we want
to be able to update the state of our users okay so first off how do we
actually do that okay how do we actually update this specific user as well as
updating the user's State itself well well we need to actually
first know which user we want to update and remember how earlier I told you that
I will show you how we can grab that well it's actually a lot easier than you might
expect so what I'll do right now
is show you what happens whenever I click on this save button so onclick let
me register this onclick event and then we'll just go ahead and console log the
user
itself and if I go into the document you'll see that if I click on this save button
which pertains to this user over
here I log the first user you can see the ID username and email are all over
there if I click on this save button it logs the second user okay so this should
tell you right off the bat that each one of these user details components are its
own instances okay so although we might
have you know the same type of user component being rendered they have their own
State they have their own identity
so they're not the same thing at all okay so knowing this I can very easily use
the ID of the user to determine okay which specific user object do I want to
edit because the way that we're going to update the state is like this we're going
to go through the array and we're
going to find the user that we want to update and then we're going to update the
entire array as a whole now there's
actually ways to do this in react without actually modifying the original
array because remember that react you want to practice immutability you want to
make sure that you are not actually
directly modifying directly mutating the users's array itself you want to do things
in an immutable way so while you
might know how to necessarily directly mutate an original arrays contents you
definitely don't want to do that in react okay so here's what I'm going to do we
need to set up our components in a
way where I can actually update the user State because right now we are kind of
in a little bit of a situation you'll notice that the user's state is actually
in a completely different component now remember that the app component is a
parent component of our user details component making this a parent to child
child to parent relationship okay but here's a nice thing though even though
our state is Define at the parent level we can easily still modify this user
state either by passing in this dispatch function down to the user details
component itself or we can actually pass in a wrapper function to take care of
managing the state for us I'll show you both ways the first way that I'll show you
is just directly passing in the set
users function so what I'll do is this so since we're going to pass in set
users to the user details as a prop and remember that you can actually pass
function as a prop to a
component so what I'm going to do is since we are using prop validation I'm going
to go ahead and make sure I add
this to the prop types so set users will be a
function is required okay I don't know why shape was
not required I should have made this required there we go all right so now
let's go ahead and get set users
and let's pass this into set users I'm sorry let's pass in set users
to user details okay so now we can easily call this
function and I'm going to show you the proper way that we're going to invoke this
function as well as updating the
state so remember that whenever we click on the save button this is where we
actually want to make the changes to the state itself
okay so what we're going to do is inside the onclick event handler function this is
where we want to make sure we are capturing the username the current state of the
username so whatever the user
updated it to and same thing for the email address okay so we need the
Updating Element in State Array
username and then we need the use we need the email address but then we also need
to make sure we have the ID of the
user which we can easily grab from user. ID now how do we actually
modify the elements inside this users array how do we do
that now there are a lot of ways that you can go about this but I'm going to show
you the right approach that the
react team actually recommends you to do so it also allows you to modify your
state without actually directly mutating the array itself and I'm also going to
mention one
more thing I'm going to use an actual LL statement instead of using a turn operator
because I don't want you all to
get confused with the amount of parentheses that we're going to have I will show
you both but I'm first going
to show you how to do it with an if else condition so the first thing that we want
to do is call our set users
function that we passed in to our user details component remember that this
function
itself is our dispatched function and remember that we can actually pass in a
callback function and the reason why we're going to pass in a callback function in
this case is because I want
access to the current state of users okay so I'm going to go ahead and
call this variable current users stat okay and then I'm going to use a
curly brace right over here because I'm going to have my code execute inside this
block over here so what I'm going
to do is I'm going to go ahead and return current users dot Uh current user
state. map so I'm going to go ahead and call the map map function on this current
user State remember this is an
array of the current state of our users and the reason why I am calling map is
because what we want to do essentially is we want to replace an element in the
array and that's actually what this is all about we're replacing a specific element
in our array and I think the
easiest way and this is kind of the reason why I think the react team recommended
you doing this on their docs
is because this is the easiest way to do this without directly mutating State
itself okay essentially what we're going
to be doing is we're going to go through each element and we're going to actually
write a condition so we're going to
check to see if the correct user is being edited and if the user is in fact
being edited then only we're going to replace the user with the updated one
I'll show you what I mean right now so what we're going to do is we're going to
pass in our callback function to the
function remember this callback function takes up to three arguments but the
argument that we care about is the
element that's in the array itself which is going to be our user I'm going to call
it current user because we have
user already being defined up over here and we will need to reference this
as well to do the comparison so that's why I'm not using user down over here okay
so now what I'm
going to do is this I'm going to write an if condition so if current user. ID
is equal to user. ID and now you see why that I am renaming this variable to
current user instead of using the same
one up top over here so basically what this is checking for is ensuring that we
are editing the correct user because we obviously don't want to manage every single
user we don't want to edit every
single user we only want to edit the user that is actually being edited okay
so if this is true then all I'm going to do is return a new object and it's going
to look like this I'm going to take every single key value pair from current
user and create a copy of it inside this new object and then what I'm going to do
is
I'm going to explicitly set the username and email address because we know that
those are two possible fields
that could be updated now if the user didn't edit any of these fields like if they
just didn't touch the fields at all
then that would be fine because by default remember that the username of
the user as well as the email of the user are set to these State variables by
default okay so if they didn't update
the email address for example then the email would stay the same so what I'm going
to do is I'm going to set the username to the state variable username
right up top over here and then same thing with the email as well so I'm setting
this email field to whatever the
value of the email State variable is now since these are the same name names I
can actually just remove the colon and I can just do it like this okay and actually
I don't need the
parentheses because I'm using an explicit return keyword so you'll notice that my
formatter actually automatically
removed those parentheses okay but when we use the Turner operator we will need
that but don't worry I'll show you how
to do that as well okay so this handles the case if the current user is matching
the user that we're editing but if we're not editing the user then all we want to
Simply do
is just return the current user and that way the
users that are not being edited won't be changed at all we're only changing the
user that is being edited hence why we
have this if check right over here now there's one more thing that I want to do
before we actually get to editing our
users we need to make sure that we are out of edit mode because otherwise we're
not really going to see our changes being reflected we'll only see it inside the
input field but we're not going to
see it in View mode so what I'm going to do is after I call set users I'm going to
go ahead and call set is
editing and this time I'm actually just going to pass it false I don't need to do
what I did
on line 14 where I pass in this callback function and just set it to the opposite
value of the current state because every
single time I click on this save button I want to exit out of editing mode and this
is very common with any application
when you click save that pretty much implies that you're exiting editing mode and
you're done okay so let's go into
our document now and let's see what happens when I click edit and I'll just change
this to let's do anen deev and if
I click save you'll see now the username is now
anev if I click edit and let's change it to an the dev for the
email you'll see that the username and the email are both reflective obviously
we didn't change the username that time so it's stood the same and if I go down
over here if I change the username from
Mike to Mike the dev you'll notice that it only affects this user and not this user
up top over
here because we have this if check right over here of course if I just uh didn't
check for this and I just did the same exact thing for everything and I'll just
show you just as an example you'll
notice that when I click save it updates it for every single user which is not what
we want so that's why this check is
very very important okay so hopefully this makes sense and just one more thing
that I do want to do nothing crucial but I only want to show the edit the the
save button when we are in editing mode so I'll just do a conditional render so let
me copy that whole thing so if is
editing so or if is editing is true and I actually don't need a turn operator
for this I can actually do is editing and use the double and peran sign and then so
only if is editing is
true then it will also render this button as well and this is another react trick
that you need to know because if
editing is false remember that this double and perent sign this is known as a
conditional and so both has to be
truthy in order for this whole statement to be true so if is editing is false
that means this whole conditional statement is false so this butt will not be
rendered but if is editing is true we
know that this bun element is going to be truthy so this whole statement will be
true and that will lead to this bun
being rendered and you'll see right over here when I refresh the page you'll see
that when I click edit now the save
button appears and if I change it and if I click save it no longer appears so
hopefully all of this makes sense now very quickly let me go ahead and actually
tidy all of this up a little
bit so as I promised I'm going to show you how we can use a Turner operator to make
this look a little bit more cleaner so
what I'm going to do is let me just remove all of this right over here and I'm
going to go ahead and do current
user. ID equals user. ID and then if this is truthy then we're going to go
ahead and return a copy of the current user while also updating their username
and email and then if this condition current user. ID is not equal to user.
ID we're going to go ahead and return what is on the right hand side of the colon
which is just going to be current
user just like that okay and I actually don't need this curly braer here so I'm
going to return it and now you
understand why I want to show you both instances because it can be a little bit
confusing with all of these uh
parentheses in the way so that's the reason why I want to show you both ways but it
works the same exact way
there you go all right now I'm going to show you how to delete elements from our
Delete Element from State Array
users array in the previous section I showed you how to update elements in an
array for your state which was actually more so like replacing an element in an
array but this time I'm going to show
you how to remove an element from our array so that way we no longer see the
element in the documents so for example if I want to delete this user right over
here it needs to be removed from the document and it also needs to be removed from
the actual user C itself so what
we're going to do is first let's go ahead and register an onclick event listener to
this delete
button and let's call this callback function and what we want to do
essentially is we want to update the state we want to update users to not
have the user object that we want to get rid of now many of you might be used to
using mutable methods such as array. splice we don't want to do that in react
because remember in a react we want to
practice immutability so we're not going to use array. splice to update our us
array
what we're going to do is we're actually going to use a method called array. filter
so think of it like this we're
actually going to be filtering out the element that we don't want okay so I
want you to think of it like that because array. filter is immutable it returns a
new array so it
doesn't actually modify the original array itself which we don't want to do so what
we'll do here is this I'm
going to go ahead and call the set users function because we're still going to
update the users State okay we still need to update the state and we do that
by calling this set users function that we passed as a prop it's the same thing
that we did when we were editing
users so we're going to also pass in the Callback function because remember that
we need access to the current state of the users so I'm going to call this current
user
State and remember this is an array so I can easily reference it and I can also
call the filter function okay so current user state. filter so if you're not
familiar with what the filter function does then you need to make sure you
understand this because you're going to be seeing this in a lot of react code
bases and you're going to be using this often so the filter function pretty much
just literally filters out elements that
you don't want okay think of it like this we don't want the element that we
want to delete so we're going to quote unquote filter it out now the way that
this filter function works is it takes in a call function and it's also known as a
predicate function and this
predicate function returns a Boolean a true or false value which we're going to end
up evaluating a conditional
statement anyways and this CC function also takes in up to three arguments
pretty much the same thing as the map function the first argument is going to be
the element in the array that we are
filtering so current user state so this argument is going to be our
user and then what we want to do is we want to write a condition that is going
to determine what elements get filtered out so in other words we want to filter out
the element that we want to delete so let's say I'm deleting the user with the ID
of one then we want to filter out
that specific user where the ID is one now instead of thinking of like that we
should think of it like this we want to
basically filter all of the users that don't match the idea of the
user that we're trying to delete because the filter method returns a new array with
with all of the elements that pass
the predicate function okay so the way that we want to write our condition is like
this I want to check if current
users's ID is not equal to the users to the user that I'm trying to delete ID
okay so if current user. ID is not equal to user. ID and remember user is this up
top over here this is going to be the user that we are trying to delete if this is
not equal
then we're going to add this current user to the new array that is going to be
returned okay
so think of it like this if if if everything so far doesn't really make any sense
think of it like this right
remember that this whole filter function is going to return a new array it's
going to return a new array that excludes all of the elements that fail
this condition so in other words if this condition is false then current
user is not going to be part of that new array that is created by this filter
function okay that new array is what is actually going to be used to update the
state of users so it's basically going to look like we are removing the user from
the
document okay so think of it like this if the user that we're trying to delete
has an idea of one so that's going to be user right over here that's the user that
we're trying
to delete and let's say the current user it just so happens that the current user
has the ID of one as well well obviously one is in fact equal to one because this
check this condition is checking to see if the IDS are not equal but one is equal
to one so since this condition
fails then that means that this user with the ID of one is going to be
excluded it's going to be filtered out from the new array okay if we get to the
user of ID 2 well two is obviously not equal to one because we are trying to delete
the user of ID 1 two is not equal
to one so two will be part of the new array the user of ID 2 will be part of
the new array of users okay and all of that gets maintained in a new array that
at the end gets returned and then we're using that new array to update the state
of users okay hopefully that makes sense but I promise you take some time and
practice the filter function it's worth it you need to understand how this function
works and not understanding how
it works is going to make it a lot more difficult when it comes to updating your
state and react okay so
now what I'm going to do is show you how this all works visually so I'm going to go
ahead and refresh the page and notice
how if I click delete we deleted the user from the document if I click delete over
here we deleted the second user
okay so basically everything that I just mentioned that was happening in the logic
of our filter function is what is
happening visually but you just don't see it underneath the hood okay you're just
seeing the service level of it but
that is how you can remove elements from the document but really what's happening
is you're just filtering out the array and you're creating a new array and then
updating the states of users with the
new array okay so it's not really deleting an element directly from the used array
because again we don't want
to do things mutably we are basically just creating a new array with a filtered out
version of it so hopefully
that makes sense so now I'm going to show you how we can add elements or
Add Elements to State Array
brand new elements to our us array and also update the state of it as well and
then have it reflect on our web page so this is actually pretty simple but
there are a few things that I do want to mention and stress later on especially
when it comes to the unique keys that
we're going to need because keep in mind that right now we're using these Keys uh
we're using the user IDs as unique keys for our components but what's going to
happen when I add an
element and then add it to this user's State variable what is the unique key
going to be right I can't just to set an ID for the user on the fly like this
remember that in a typical application the identifiers the unique IDs are
typically set by the database or set on the back end somehow either using a uuid
or whatever okay so I will address that towards the end of this section of our
of our uh tutorial so what I'm going to do is I'm going to go ahead and set up a
simple
form and we can actually do this inside our app component so I'll set up one
real quick let's do this I'm not even going to use the form element I'll just do
inputs um we'll do input and then I want to set up a
label and this will be for [Music]
username ID username we will need some State as well I'll do that in just a
second and then let me make sure I have one for email
then email okay so it looks like this I will actually add this up top over
here and you know what I will yeah I'll just leave it like this for now and let's
see what it looks like okay let me
wrap this inside their own
divs okay there we go and last but not least we do need a button so you know what
actually I will
wrap this in a form so that way I can put the button
there okay so we have our username email and add user uh I will do this let me
add a couple of breaks just so everything looks a little bit more organized okay
perfect so let's go ahead
and do this let's add some state to bind to our username and email fields
so I'll just go ahead and keep it simple I'll just
use a simple
string but if you want you can use an object to encapsulate all of this but
I'll just use an individual string for each
one okay and let's go ahead and set the value and we will need event
listeners or each one of these so let's do on change that's the
event listener that we want to register basically the tech changes whenever we
update the input Fields
value so all we're going to do is call set username and then pass in e. target.
value again this is stuff that we've
already done already so that's why I'm kind of speeding through it and let me copy
and paste this and just call set
email okay so now when I click on add user
when I click on add user what it should do is it should add it to the users
array and then it should display in the document okay now let me go ahead and just
fix this part where you can see
that it is refreshing the page whenever I click add user that's because we have a
button inside our form and we haven't
overwritting the onsubmit default value so we can very easily do that by just
adding this onsubmit event listener and then we can just do e. prevent default
and that will ensure that we don't have the page refresh when I click
on this button okay so just wanted to mention that very quickly so now what
I'm going to do is this so whenever I click on the onsubmit or whenever I
click on add user it's going to go ahead and Trigger this onsubmit event because
we're inside our form that's just the default Behavior right so so I'm going
to go ahead and conso log username and email just so you can see what this object
looks
like so I click add user right now or I'm sorry not object the current uh
values right now it's currently empty but if I type something you can see that
it appears right over here so what we want to do is we want to wrap this inside an
object and then we want to add
it to the array of users but we also need an ID for the user itself okay so
this is the part where it gets a little bit tricky right because now you're
wondering well what exactly do I use for
the ID now I'm just going to cut right to the Chase and I'll explain later on why
this is very important but the best
thing that you can do when it comes to adding elements to the document dynamically
and needing to find a way to
associate a unique key with the added elements because keep in mind that these
elements right over here we are assuming that these are unique IDs that come from
some API and those are typically
generated by the database right and an application where you need to create a
list of data on the front end side that is not going to be generated by the backen
at all you're going to need some
unique identifier to identify each element and I've actually ran across uh
I've actually ran across this problem myself a couple years ago and I've had some
discussions with some other more
knowledgeable people than I am and we came to the conclusion that one of the best
ways to handle this is actually by
using an incrementer to keep track of all of the unique IDs okay so this is
what it's going to look like so what I'm going to do is I'm actually going to
create some
State and I'm going to call this counter set counter this will be a numeric value
and I'm going to hardcode this just as an example I'm going to set the
I'm going to set the default value to two because we have two elements by
default currently I'm going to set it to two and then I'm actually just going to
increment it every single time okay well
actually I'm going to set it to uh I'll set it to three okay so what I'm going
to do now is I'm going to create this new user object I'm going to set the
username and email email and then I need to set the
ID to be what counter is so counter will be that right over here counter will be
three since that's the current default value so when we first add a user the ID of
that new user added will be three and
then all we need to do is just increment the counter by one so we can just easily
do that by simply just calling set
counter and then we want to make sure that we have the current value of counter so
we're going to use the
callback function and pass in that argument and
then do current counter + one okay and then we're going to go
ahead and we're going to call set users and then we're going to add new user to
the array and this is actually very easy the easiest way you can do this is by
calling set users passing in the
Callback function so you get access to the current users State and and then you can
just pretty
much create a new array you create a new array and then use the spreader operator
on the
original array so this will take every element that is inside current user
state which are all of these user objects and whatever has been added to it and
then unpack it and then place it
in a new array preserving its order and then all we need to do is we can add the
new user element at the end just like this and again this does it in an immutable
way without directly mutating
the array itself okay and if you wanted to place the new user in the front you just
put it right over here before you
spread the current user State okay so hopefully this makes sense now let's go
ahead and refresh our page and let's add a user so let's add
Tim and you can see now it works I can add more
users there you go I can even delete these users and add it again but now you'll
see that the ID is five because
it's preserving that counter as the ID it's using whatever the value of counter is
okay now I do want to address this
because a lot of people will be wondering well can I just use the index of the
element in the array as the ID so
what people are talking about is this so remember that the map function takes up to
three arguments the first argument is
going to be the value in the array itself the current value the second element is
going to be the index
so the current elements index okay so for example the index of this first user
object is going to be zero and then this one is going to be one and a lot of people
are wondering well can't I just
use the index as the key and as the ID to uniquely Define these
users well you can't I mean you surely could but you will run into a lot of
weird issues that you won't understand why it's happening because you use the
index as the key now let me actually rephrase this you could actually use it as an
ID just not as a key when I say ID
I mean the ID of the user object there's nothing wrong with that but you cannot use
it to Key your component that you
are rendering to the document just to be more precise now in a nutshell don't use
indexes as your keys there are basically a lot of issues that can come across such
as performance impact and a lot of
bugs so just use an incremental counter especially if you are just
building some kind of application where you need to add data that is displayed on
the front end that has not reached
the back end just yet okay because again there are a lot of examples where you need
to add information to the screen
via a form and you have not send that data to a server so the server can't
generate a record for that data so you can't use the autogenerated ID that the
server gives you as a unique identifier so in situations like this using a counter
is perfectly fine just don't use
the index of an array okay so hopefully this part makes
useEffect Hook
sense in this section of our react tutorial I'm going to teach you about the use
effect hook if you've been
watching you have been introduced to a hook called the use state hook which is
used to define state and also manage state I'm going to teach you about the
use effect hook because this is a very important hook that every single react
developer must understand and be able to
use inside out because the biggest thing when it comes to react is knowing how to
properly use this use effect hook to perform side effects in your application
because often times you will need to perform side effects in your application so
first of all what exactly is a side
effect a side effect is basically anything that you perform that is outside of the
scope of your component
or in the broader scheme outside the scope of your application itself so for
example if you need to make a network
request that's outside the scope of your application because once you make an API
request to some external server your
application has nothing to do with it it's just going to get back the response from
the server itself another example
of a side effect is accessing local storage which you if you aren't familiar with
local storage it's basically just a
way for you to store data in your browser that you can access later on
another example of a side effect is being able to directly manipulate the document
itself so if you want to
manually update the title document if you want to manually insert an element
into the document that's a side effect if you want to manually register an
event listener onto your document such as whenever the browser is being resized
or if the user is scrolling these are examples of side effects there are a bunch of
different side effects that you'll come across these are just common
examples that a lot of developers often need to tackle on so I'm going to teach
you all about the use effect hook how to properly use it I'm going to teach you
about the different behaviors of this
use eff hook so that way you fully understand how to properly use the use effect
hook
so I know right now inside our app component we have a lot of stuff going on and I
want to make this as simple as
possible because when there's just too many things on our screen inside our code it
can be very overwhelming to just
track every single thing so I'm going to make this very simple I'm going to remove
uh this username and email I'm
going to remove all these users you don't have to remove this if you don't want to
I just think it's better for us to remove this just so that it makes it
easier for us to see what's going on instead of just tracking everything that is on
our in our code so what I'm going
to do is I'm going to keep this counter State and I'm going to set this to zero and
I'm going to create a
button and I'm going to go ahead and give this button a text called click me and
then I'm going to register an
onclick event listener on this button and every single time we click on this button
I'm going to update the counter
by one so this will basically track the amount of times we as the user clicked on
this button so let's go ahead
and update the state just like this and then I'll go
ahead and display that text to the user you clicked the
button counter times okay very simple stuff just to show you how this is going
to work you can see over here we have our text currently it says you click the
button zero times when I click this
button for the first time it'll update and each time I click on it it's going to
basically by one very straightforward
stuff okay now what I'm going to do is I'm going to go ahead and import my use
effect hook now remember that the use effect Hook is also a function so let's
import that first from
the react package and the way that we're going to use the use effect Hook is like
this so we're going to go ahead and just
call use effect like a regular function and this use effect hook takes up to two
arguments the first argument is mandatory it is known as a call back function or an
effect call back okay so
this is just going to look like a regular callback function and then the second
argument is
optional but it is very crucial to understanding how to properly use this
argument okay the second argument is an array or better known as your dependency
array or a dependency list it's basically just an array okay I'm going to explain
more about this uh in just a
second but first what I want to do is I want to Omit this because I want to inside
my callback
function of my use effect hook I want to basically just directly manipulate the
document and there are a lot of
different ways that I can do this I can access local storage I can update the title
of the document so what I'll do is
right now you can see that the title of our document is V plus react that's just a
default title and what I can do is I
can just set the document title like this to react tutorial and so what's going to
happen
happen is whenever our app component is rendered whenever it's mounted to the
document our use effect Hook is going to go ahead and invoke this callback
function okay now remember what I said based off of how you set up your use
effect hook if you have the dependency array or not it's going to contribute to
the behavior of your use effect hook and how it calls your functions and how many
times it calls your functions so basic
basically right now in this current state every single time my app component
is rendered and rendered it's going to go ahead and invoke this callback
function okay so just so you know that there are different life cycles of a
component so for example when it first renders to the document after it renders and
then when it needs to unmount from
the document okay so in the initial stage we're mounting the component we're
rendering the component to the document and then in other situations our component
May perform a render of itself
and a lot of things can trigger a rerender one common example is whenever your
State updates your component can
render and I'll show you that in just a second so Watch What Happens here so
when I refresh the page you can see that the title is updated to react tutorial and
it does it so fast that you don't
really notice the update happening in real time because it's just happening like
instantly okay but I want to show
you what happens when I console log this message
rendering if I refresh the page you'll see that it's going to render it's going to
log twice now this is because we are
in strict mode which is what is enabled by default you can actually turn us off by
just removing this react strict mode
right over here and then you can see now it renders once okay you don't have to
turn it off
but just know that you can if you want to by default in production strict mode is
off
okay so when I refresh the page you can see that it is going to do its initial
invocation of the Callback function now watch what happens when I click on this
button you'll notice that every single time I click on this button this rendering
is being logged to the console
so that implies that this callback function this effect callback is being invoked
because obviously in order for
this console log to be logged to the console it has to have this function
being called itself now why exactly is our callback function being
invoked so as I hinted earlier we have some State over here we have a counter
every single time I am updating the state of counter what happens is react
is going to unmount and then rerender the component reflecting its new state
okay so over here you can see that I am updating the state of counter so it's going
to go ahead and render app and
whenever we render app remember what I said earlier when app is rendered by default
it is going to go ahead and call
the Callback function of this use effect hook and that is why this console log is
being rendered to the document okay hopefully that makes sense I can even go
a step further and I can actually concatenate this react tutorial title with the
counter and then that way the title will tell you how many times it was updated
okay so 18 times 23 times
etc etc you get the idea so hopefully this makes sense each time I make an
update to my state in this current usage
of the use effect hook where I don't have any dependency list or dependency array
added At All by default it is
going to call this callback function every time our component rerenders okay
useEffect Dependency Array
now I want you to see what happens when I add the dependency array remember this
array is optional you don't need to have this but just know that depending on how
you use this dependency array whether you omit it or add it to your use effect
hook or if you add certain elements to this dependency array which I will teach
you about that in just a second this will change the behavior of how your use
effect hook works so let's show you this
example of what happens when I add an empty dependency array to my use effect hook
okay so I'm
going to go ahead and refresh the page now you can see that initially what's going
to happen is it's going to go
ahead and call the Callback function of my user vub okay and it does it twice
because that because we're currently in strict Noe but watch what happens when I
now click on the click me button cause
it to update the state of my counter okay I'm clicking the button but notice
how the rendering function or I'm sorry the rendering is not being display to
the console anymore and you can see that the title still says react tutorial zero
okay notice how that is happening right now because I added my empty dependency
array if I remove it if I remove it you can see that now
it is going to log rendering every single time I click on the button why is this
the case so when you add a
dependency array and more specifically when you add an empty dependency array to
your use effect call what happens is
the Callback function the effect callback is only going to be invoked one
time only which is when your app component initially renders and any
state that is updated is not going to cause a call back to be inv or it's not
going to cause the use effect call back to be called okay and it's pretty
evident over here because I am making updates to my counter State variable but the
user effects call back over here is
not being called again and again and again that's because I have an empty
dependency array okay now I will mention
right off the bat this is a very useful situation when you need to make an API
call as an example so let's say if you are trying trying to fetch the user from
an API and you want to render it to the document and you don't want to refetch the
user every single time you're making
updates to the state then you would want to have an empty dependency array added
to your use effect call okay so generally this is very important it's
very common when you only want your use effect hook to call the Callback function
one time only now the next
important thing to understand is the dependency AR and what we can add to our
dependency array so as I mentioned
earlier not having the dependency array will cause your use effect call back to be
invoked upon every single render
adding an empty dependency array will only allow your call back for your use effect
hook to be called once
only no matter what state variables change but there are situations where
you do want your use effect call back to be invoked whenever your state is being
updated now let's say I do in fact want the use effects call back to be invoked
whenever
the counter State variable or any state is being updated what I want to do for
this dependency array is I want to specify which state variables are a
requirement for this call back to be invoked so this is the reason why it's called
a dependency array because the
use effect hook depends on those State variables in order for them to change to
cause the Callback function to be invoked okay so for example by adding
this counter State variable to this array what I'm basically doing is I'm saying
okay whenever a change occurs to
counter call this callback function only when counter changes so now watch what
happens if I refresh the page and if I click the click me button you'll see that
when I click on this button it's
going to go ahead and call the call back function again okay if I click on it twice
or if I click on it a second time
it's going to call the function again and again and again and again and again and
this is the behavior that we wanted
or the original behavior that we had when we didn't have our dependency array
okay so hopefully this makes sense now just to show you another example perhaps
you don't want to necessarily use the counter State variable as a dependency you
may want to depend on a different
state variable so let's do this let's say we want to click on the button x amount
of times okay and then we want to
have a synchronize button to basically synchronize the state to show us exactly
how many times user clicked on the button itself okay so what I'll do is this I'll
create a variable another
saate variable called sync set sync and this will just be a simple Boolean value
that will just all alternate between false and true okay and this is a very common
approach to uh being able to detect
whenever something is occurring so what I'm essentially doing is I want to add
sync as a dependency to this use effect hook okay and then what I want to do is
this I want to add another button and then I'll have the text be
sync and then whenever I click on this button I'm just going to go ahead and just
update the state of sync I'm I'm
basically just toggling it so I'm going to call set sync and then uh current I'm
just going
to set it to the opposite value of it so the basically if sync is true it's going
to update to false if sync is false it's
going to update its true so we're basically toggling between true to false false to
True okay and whenever I do
update sync what's going to happen is in or in order for this use effect hook to
be invoked sync needs to change okay so Watch What Happens I'm going to go ahead
and click on click me as many times as I want now keep in mind that the counter
state is still going to update and it's
still going to display in the document just fine that's that's normal but in
order for my use effect hook to invoke this callback function and update the
documents title manually I need to make
a change to the current state of sync in in order for this call back to be invoked
so watch what happens when I
click on the sync button you'll notice that when I clicked on the sync button
we logged rendering to the console and then you you'll notice that the title was
updated from re uh it was updated
from the previous one to react tutorial 20 I can refresh the page and show you
again okay so right
now the Callback function of the use effect Hook is called one time upon render
that's default Behavior
okay react tutorial zero so in the current scope of this callback function
counter the value of counter is currently zero that is why it says react tutorial
zero I'm going to go ahead and
click on the button 10 times and you'll notice that the title has not changed at
all but the moment I click on the sync
button the title now is changed and you can see that rendering was logged to the
console okay so hopefully this shows you
how powerful this dependency array works it's only going to go ahead and invoke
this callback function whenever specific State variables are
updated one thing that I do want to address is you'll notice that we have this
linting warning over here and it's
telling us that we're missing a dependency called counter you'll notice that if I
add
counter it just goes away the reason why this linting warning is occurring is
because basically whenever you're using a state variable inside the Callback of a
use effect hook react wants you
especially if you have a dependency array react wants you to add that as a
dependency why because you're literally
using a state variable that could possibly change throughout the lifespan of your
component it could possibly change okay so if that state variable changes we
want to make sure that when we call our use effect callback function that we
have the latest value of counter okay because right now over here my omitting
counter I can update counter as many times as I want but this use effect hook the
scope of it we'll never really know
okay and so you might run into some issues sometimes you can get away with running
into some issues but generally
you shouldn't use State variables inside a USC H if you don't intend to add it to
the dependency array itself okay now obviously by adding this counter variable to
my dependency array it would
not give me the behavior that I originally wanted but this is essentially how you
would get rid of that warning issue you could also just
not use the counter at all and you can just leave it like this and that would
be perfectly fine so there are different there are many different ways that you can
go about this but I did want to
address this issue
Fetching Data Example
okay so now I'm going to show you an example where we can fetch data from an
AP pii which is another side effect that you will often need to perform in your
react application because whenever
you're building an application you typically want to serve data to a client you
want to render that data somehow to
the user and where does that data come from a server an API you name it so I'm
going to use this online server this is free and they have it set up with mock data
so I can fetch some posts I can
fetch some comments I can fetch some albums what whatever it is I'm going to show
you how to make these simple HTTP
requests okay let's go ahead and get started so inside my code now one thing
that I also want to mention is that when it comes to the use effect hook you can
have as many use effect calls as you
want so for example I can set up another use effect hook right down over here and
of course this will call its own
callback function another thing that I should also mention is that use effect hooks
the callbacks are going to be
called in order that they are implemented so for example this use effect hooks
callback is going to be
invoked first and then this one and then any other subsequent use effect hooks that
you may have after the second one
will be called afterwards so they are in order okay so what I'm going to do is I
want I'm going to go ahead and use the default fetch API that is built in to
our browser API to get this data from this Json placeholder server
so all you have to do is just type Fetch and you'll see that it pops up right over
here and we need our URL the server
that we are going to fetch the data from now again if you're fairly new to front
end development and you don't understand
the concept of fetching data or retrieving data from a server which I assume most
people who typically start
off with front-end don't really have any backend experience let me briefly explain
what's going on so This Server
this online server is basically just going to serve data to any client that
wants to make requests to it so you can see over here they have a couple of
endpoints that they already set up so
I'll show you a simple one we have this users endpoint right over here and we
can make HTTP requests okay so that is the protocol that we are using and the
specific method that we would be using is a get request method to get this data
because we're only trying to retrieve this data and serve it in a readon mode we're
not trying to create data or
update data on the server side so I'm going to go ahead and take this URL right
over here and I encourage you to
do this yourself as well take this endpoint or any endpoint that you choose
to use and you're going to paste it right over here as an argument for this fetch
function okay that's going to be
the first argument to this fetch function is the server URL that you want
to retrieve the resource from okay so in this case I'm going to retrieve this
users resource which is going to give me an array of objects which are specifically
users okay so now with the fetch API we do need a second argument actually we
don't really need this but I will mention this just just for the sake of it because
when we show examples of
making post requests you will need to know how to set up this second argument
but this second argument allows you to set up options for your request so by
default the request method is going to
be a get request which means that you're going to get data which is what we're
going to do so I don't actually need
these options but what I'll do is I'll set the method to get just to show you
how this happens and if we were making any post requests where we are sending
request bodies or even a put request or
patch request which I'm sure that this terminology might be brand new to you
all then we will need to set a request body property which is the body property
itself and then this is where you would actually specify what key value pairs you
want to send to the server so if I
wanted to send a username I would specify that in this body object now
obviously we're not going to be sending any data at all so we're just going to
leave it like this okay so now what I'm
going to do is I want to make sure that after I fetch the data I am going to be
able to retrieve the data from the response okay because when you fetch dat data
from some server you're basically
requesting the server for that data and then the server is going to send back a
response now in this situation we're
going to get a response back which is an array of users and we need a way to
actually handle that response okay so
before I do any of that I do want to show you the API call occurring in the browser
so what I'll do is I'm going to
go into uh my application over here I'm going to refresh the page and I want to
show you the network tab this is a great tool to inspect API calls or any API
calls any network calls that are happening on your client side application so let
me zoom out a little
bit so right now I have it filtered out to fetch xhr which basically these are
just API requests to some server and you can see that right over
here it is making two API calls and remember what I said earlier that your use
effect tooks are going to be invoked
twice which because we are rendering the component twice it's going to cause our
use effect callback functions to be
called twice as well because every single time we render the app it's going to go
ahead and invoke our use effect
hook at least for this one right over here so you can see that it is definitely
calling this API if I uh
expand this a little bit you can see the request URL is this URL right over here
the exact one that we pasted into this
argument over here and then you can see that the request method is a get request
and then the status code is a 200 which
just basically means it was a successful response from the server and there's a
bunch of other things we're not going to really worry about that right now and
then if I click on preview this would give me a preview of the data that was sent
back from the server you can even
you can even just click on response to see the par version of this okay so
hopefully this is straightforward now as
I mentioned couple minutes ago that we want to handle the API call itself
because right now we're just calling fetch but we're not actually handling the
return value from Fetch itself okay
so one thing that you must know is that fetch is going to return a promise now
if you're not familiar with promises you definitely want to brush up on
understanding what promises are in
JavaScript that is actually I would say a requirement a prere when it comes to
building any
application in JavaScript but basically promises have States they have a pending
State they have a fulfilled State and then they have a rejected State okay so
when I call this fetch function it's going to return a promise and that promise
will be in either one of three
states so by default it's going to go ahead and call this API and we need to
make sure that we properly handle this promise okay so by not handling this
promise it's always going to stay in the pending State even if the API call fails
we need to make sure that we properly handle this promise to get it to the correct
status so that way we know
whether or not the API call succeeded or if it failed okay so in order to handle
this promise there's one of two ways I'll show you both the first way is you can
use do then so after you call any
function that returns a promise the promise object itself is going to have this
then method or or it will have
catch or finally so it's very similar if you've used a try catch Clause before or
try catch finally so when you call do then this is basically handling the
promise when it resolves which resolving A promise is actually a good thing which
means that the promise succeeded okay
whatever whatever function uh that it was invoking underneath the hood it succeeded
it was in a resolved state
which typically means it's a good thing so that means that the API call succeeded
it returned a status code of
200 with our data so by calling the then method what we need to do is we need to
pass a callback function now this callback function the argument that we're going
to pass in is going to be
the data that is resolved from the proms itself so this is actually how you
access the response from the API so I'm going to go ahead and call this response
okay and for now I'm not going to do anything special I'll just console log
response okay and I want to show you
what this looks like because we know that this API call is succeeding so I'm going
to go to the console and you can
see already that right over here we have our response object being log
remember whenever whenever our app component renders it's going to go ahead and
invoke our callback functions for
use effect at least once okay so over here we can see that this callback
function was invoked and you can see that right over here it is being invoked twice
it's calling the API twice because
of what I said we're in strict mode and that's fine so you can see that the
response is logged twice that's okay and
then you can see that the status is 200 which is good means a successful response
from the server and the fact
that this response object is defined or the fact that we're even in this scope
of our callback function just shows you that the promise resolved the API call
was successful otherwise we would be in the catch part which I'll show you in just
a second so you can see if I
actually click on body right over here maybe not body but there should be I
guess I guess it maybe is body but we need to parse the data that's okay so here's
what I'll do we actually need to
parse the data because this is just a response and we need to actually get the data
from the response object itself
I'll show you how to do that right now so what I can do is I I can actually just
return response and then call this
Json object this will actually return a promise as well so return response. Json
this returns a promise as well and then we can actually call then again because
when I
return response. Json this would also return a promise and I can actually handle
that Promise by calling then
again right over here and whatever value that promise resolves can be passed into
this callback function over here so in this part over here the actual argument is
going to be the actual Json data so
if I show you what it looks like right now in the console you'll see that right
over here on line 20 which is what I am
logging over here this is the actual Json data the Json array that is
returned from the API itself okay we just needed to make sure that we parsed
the response by calling response. Json and then handle that promise again by
calling that then okay if this is all
brand new to you it might be a little bit confusing at first but I promise you that
if you just read up on promises and
practice them it'll make a lot more sense okay so you can see that I can see all of
my data right over here and I can
access it however I want I can render it to the document I can do whatever I want
okay now I want to show you a situation
where the API may fail so let's say for example if I just uh added this
incorrect API endpoint right and if I refresh let me go to my network tab if I
refresh you'll see that right now it's giving me a 404 which means not found and
that's because the API endpoint is
not found now because we are trying to fetch an invalid endpoint what's going
to happen is the fetch function when it Returns the promise the promise itself
is going to be in a rejected state after we handle it so it's not going to go into
the then callback function call
it's going to go into the catch function call okay so this is how you can perform
error handling so what I can do is I can pass in this error as an argument to the
Callback function for catch and I can actually just log the error as so like this
and then if I refresh the page
you'll see that uh let's see if it logs anything doesn't seem like it will log
anything it seems like the error object
is just empty but uh what I can do is I can actually just console log invalid
endpoints and that should be logged right over
here uh let's see maybe
not I guess maybe not I guess if I guess the way that
fetch works is that it doesn't actually reject the promise so that's a little bit
strange on why it does that but um
it should it should actually log some error so I actually just Googled this
and it seems like the fetch API does not reject the promise if the API returns a
404 which I think it should in my opinion but it doesn't so that's okay but I'm
pretty confident that if it
returned anything like a 401 or a 403 status code which is typically has to do with
uh the user not being authenticated
it should reject at least in my opinion it should but if you use a different API
Library such as axios for example
typically different API libraries will handle errors differently but I I know from
experience axos will in fact uh
reject the promise so it will go into this catch block over here if the API
endpoint isn't valid but even then when you handle the API response this is
exactly what you want to do using then and catch now I'm going to show you the
other way where instead of using then.
catch we're going to use a combination of a tri catch block as well as async
and AE okay now if you're not familiar with the async AE syntax you definitely want
to make sure you learn this because
you will be seeing this often as well in react code bases and even some examples
of documentation and tutorials will imply that you already know how async in a way
works but basically what I'm going
to do is I'm going to remove all this okay and I'm going to I'm going to remove
this object over here because we
don't need this object right now because by default fetch will default to a get
request and that's okay let me remove
this extra S at the end so what I'm going to do is this first I'm going to
go ahead and create a function inside my user effect callback function and this
function is going to be an asynchronous function okay so I'm going to go ahead
and call this function fetch users and I want to make sure in front
of this function keyword I add the async keyword okay literally just added the Asin
keyword in front of my function
makes this an asynchronous function now all this literally means is it returns a
promise and it allows you to use the await keyword inside the function itself
okay now why this is important is because remember our fetch function the fetch API
this function itself returns a
promise okay now there's another way to handle promises instead of using the then.
catch syntax we can actually use
the await keyword and the way that it works is all you do is you use the awake
keyword in front of
any method call that returns a promise so for example our fetch function it
returns a promise so what we can do is we can add the await keyword in front of
this fetch function call and what this does is it basically says okay wait for
this promise to resolve or reject and then proceed on with the rest of our
logic with the rest of our code okay okay so in other words it kind of like blocks
the rest of your code until this
is complete okay until it goes from the pending state to either resolved or I'm
sorry either fulfilled or rejected we typically want to pair this
with a tri catch block because it allows us to perform error handling okay so
what I'm going to do is I'm going to await this fetch call but I'm going to go
ahead and make sure I sign this to a
a variable called response and now this response variable is going to be the
actual response object itself not a promise because remember fetch returns a
promise when we await any method call that returns a promise you get the actual
resolv value if the fetch call
fails it's going to go to this catch block over here and then you can handle the
error accordingly so in other words
you don't get the actual resolve value okay so let's go ahead and paste our URL
again so let's go back over here copy that let's paste that URL right over here and
remember that we do need to do
an additional step where we need to actually call response. Json to get the
actual Json data so I need to go one extra step and call
response. Json remember that response. Json also returns a promise as well so
if I don't await this promise if I don't if I don't await this this Json call you
can see that if I hover over Json the data type of my Json variable is a
promise but the moment I add the a keyword in front of my response. Json method
call the value of Json is no
longer a promise it's the actual resolved value that the promise gives you when the
when the promise f is
fulfilled when it's successful okay this is very important to understand like I
said because you're going to be dealing
with this often especially if you're building Dynamic applications that fetch data
which is very common so I'll go
ahead and just conso log this variable and then I'll console log the error object
down over here okay
and then now what I'm going to do is I'm going to go ahead and inside my use effect
hook I'm going to call fetch users but I'm not going to use the await
keyword first of all I can't because I'm not inside an asynchronous function if I
try to you're going to see that's it's
going to give me an error because it says cannot use keyword a out outside an async
function now you might be
wondering well couldn't I have just added the async keyword in front of this
callback function now you actually could
but you're going to get this linting warning and the reason why it tells you this
is because it has everything to do
with preventing raise conditions so that's why they don't recommend you make the
Callback function of the use effect
hook an async function okay so that's the reason why we did it this way and in
fact this is actually what you would see in an example on stack Overflow or on any
uh help website that is asking how
do you fetch data properly inside use effect hook the idea is you create a wrapper
function and then you just call
that wrapper function like this okay so again this is just a very Bare Bones
simple example for absolute beginners in a more advanced scenario You' typically
want to make sure you handle the
situation where the request fails we're not going to get into that right now but
typically you want to use libraries such as axio with react query cuz those
libraries handle that kind of stuff for you okay but uh what I'm going to do now
is I'm going to leave it like this and I'm going to show you exactly how this works
so I'm going to go back to my tab
over here I'm going to refresh the page you're going to see that my data uh well
the users's endpoint was
called and you can see that everything is successful on line 19 where I am logging
this Json variable you can see
that I have my user data now notice if I were to not
if I were to remove the await call look at what is actually logged in the console
you'll see that it logs Promise
This Promise object and the status is pending okay the status is
pending okay so hopefully this shows you why you need to make sure you handle
your promises accordingly either by using then. catch or async AE
okay now this next thing that I'm going to show you is not really an advanced or
intermediate topic it's a very simple
AbortController
concept to understand so I do want to show you this so it has to do with what I
mentioned earlier about uh handling
the request when it either is supposed to be cancelled or if the component is
unmounted because let's say for example let's say if we are rendering our app
but then something causes the app to unmount maybe the state is updated
whatever it is we don't want the request to go through we want to actually abort
the request okay so what we're going to
do is we're going to use something called the abort controller and it basically
allows you to control the
request so you can have it be aborted you can basically cancel the request if
it needs to be okay so what I'm going to do is inside my use effect callback I'm
going to go ahead and create an instance of the abort controler CL class this is a
built-in API so I'm going to do const
controller equals new abort controller just like this whoops just like that okay
and then the
important field that we want is I actually want this signal field right over here
okay the
signal field I'm going to show you how we're going to use this field okay but
basically this is going to give you the
abort signal property and it basically gives you
information about the aborted request if it is aborted
okay now what I'm going to do is when I make my API call so I'm when I call
fetch we want to pass in that second argument that
object okay but this time we want to set this property signal in this object and
then what we're going to set it to is controller. signal okay and this is
basically going to communicate with the request if the request needs to be aborted
or not okay so we're going to
leave it like this and then what I'm going to do is inside my use effect hook
at the end over here and I didn't actually cover this in the previous section when
we first talked about use
effect hook but I'm going to talk about it right now so your use effect hook has
uh has current stages right when it first renders the component your use effect
Hook is called
but then when your component unmounts when it kind of like UNR from the document
there is a stage known as the
unmounting phase or the cleanup phase and this is basically where you want to take
care of either cancelling your side
effects such as canceling API requests can uh unregistering event listeners from
the document because you no longer
useEffect Cleanup Function
need them running in the background and leaving those events registered when you
are actually not needing them could could potentially cause performance issues and
lead to memory leaks so you want to make sure that you handle this
case all the time whenever necessary so the way that this is going to look like is
this your use effect callback
actually allows you to return this callback function right over here and this
callback function is all of the
logic that you want to perform to uh handle when your component unmounts so
in a situ in a situation like this when my app component unmounts an example of
that would be if we update some State and it may cause the component to render
it goes through the unmount stage first and then it renders the component again so
when that happens we definitely want
to make sure we are canceling any API requests because those API requests are no
longer valid they are stale and we
don't care about them anymore so they the way that we can do this is we can
reference our controller instance and
just call the aborts method like that okay so
I'm going I'm going to go back to my page and just watch this if I refresh
you can see that right over here it's pretty evident what's going on okay so
you'll notice that the first API call was cancelled because I have my abort
controller cancelling or aborting the API call but notice how the second one
is successful you might be wondering well it's pretty obvious why this is happening
and maybe if it isn't obvious
I'll explain so remember what I said we're in strict mode right now so by default
our use effect Hook is going to
be invoked twice because or I'm sorry our use effect call back is going to be
invoked twice because the app is
rendering two times okay that's going to cause our use effect hook to render one
time for each render of the app okay now
it renders once but then it aborts this API request
because the component unmounts and then the component renders again but the
component doesn't get unmounted the
second time okay so what happens is on the second time it's going to go ahead
and actually make the API call and since we're not unmounting the component this
call back function down over here that we are returning this cleanup function is
what it's called never actually gets
executed okay so hopefully this makes sense the cleanup function is called the
first time because we are unmounting the
components okay then the component is rendered the second time and then this
cleanup function is not called the
second time okay but if there was an instance where we were in fact going to go
ahead
and unmount the component and based on I guess the status of the controller
itself based on that it would then tell us if we needed to cancel the request or
not and actually if I were to conso log controller and then if I were to conso log
the signal this would actually give
us some information about the request if if it has been aborted or not so you can
see over here uh right over here it says abort signal aborted false so it was not
aborted on the second time but the first time it definitely was it it definitely
isn't in fact I could probably console
log the signal down here and it should tell us that it was aborted so you can
see over here in the cleanup function in the scope of this cleanup function over
here when I after I abort the API
request the signal has this object over here and you can see that the aborted
property says
true which basically tells us that the request was in fact aborted okay so
again this is nothing crazy to understand it's just something that I think is worth
noting but like I said
when you use librar such as react query they take care of this stuff underneath the
hood
for you so you don't need to worry about it but since we're not using react query
right now I think that is more for an
intermediate level or maybe once you get used to understanding how API API requests
work then you should get to
using react query okay but hopefully this part made sense now before we do move on
from
POST Request Example
Network requests I do want to show you an example where we can make a post request
to the server
so a post request if you're not familiar with it is the type of request that you
would make whenever you want to create
some kind of record or resource on the server side a realistic example of this
is let's say for example you want to create a new user account on some platform so
what you would do is you
would sign up you would enter your display name your username email password all
that kind of stuff when you
click on the register button it's going to submit your data to a server via a post
request
okay post basically is just a different request method so when it comes to network
requests via HTTP you have get
requests you have post requests you also have put in patch for updating a record on
the server side there are a bunch of
different types of requests okay so you basically make a post request you send that
data to the server side via the
request body and then the server side will take care of saving that information on
the database okay so what
we're going to do is we're going to set up a very simple post request where we are
going to create a post like a
literal post like a blog post okay we're going to use the Json placeholder server
as well because they do have a post
request endpoint that we can take advantage of it doesn't actually add new posts on
their endpoint it just it
probably uses some kind of mock service worker or something behind the scenes to
make it simulate adding posts to the
record to the existing records so we're going to do that so what we're going to do
is I'm going to set up two form
Fields because this endpoint is going to require I'll show you it's going to
require a title and a body as well as a user ID the user ID we're just going to
hardcode that but the title and body
will have ourselves type information into some text fields and then we'll submit
that to the server okay so here's
what we're going to do first let's define some State I'll go ahead and call this
post um I'll call it blog post data set blog post
data and then this will basically be an object that is going to represent what we
type into the form Fields we're just
encapsulating everything in a single object instead of defining it as individual
strings or state variables
that are strings so we're going to need our title which is going to be a default
value of an empty string and then our I
think it's the body let's double check uh body up and that's going to be an
empty string as well okay and then now let me go ahead and set up to form
Fields so let's set up a form we're going to need a label and we're going to call
this label
title and let's set up the input field and then the ID of this is going to be title
it's going to match whatever
this HTML 4 value is so title title and then let's go ahead and
set the value to blog poost data. tile so we're basically binding this uh this
state objects title field to this value we need to make sure we also handle the
onchange event so every single time we type into our input field or if we paste
something or if we cut the text from the input box that's going to trigger this
onchange event so we want to make sure
we update the state and I showed you how to do this in previous sections when we
covered I believe it was the register
form yep the register form so I showed you how to update the state when it's an
object so this will be a little reminder
we're going to call the set blog post data function this updates the entire object
itself but we're going to do some
JavaScript magic so first I'm going to pass in this callback function to get access
to the current state of blog post
data so I'll just call this current blog post data and I'm going to create a new
copy of the current state like this so I'm going to use the spreader operator on
the current blog post data object and
then I'm going to explicitly override the title because that is what we are
updating and the value of title will be
e. target. Val because that is what we are uh that is the actual value of the
input field okay so every single time we type or paste something or just cut the
value of the input box it's going to trigger this onchange it's going to go ahead
and call set blog post data and
then update the object but it's going to specifically update the title field okay
we're going to do the same exact thing for our body so let me wrap this in a div
and let me just go ahead and just copy this whole thing paste this and just change
everything up so I'm just going to call this body call give the ID body
and then just call this label body and instead of blog post data. tile it'll be
blog poost data. body and then then
we're going to go ahead and do the same exact thing when we call said blog post
data but this time it's going to be body
instead of title okay so now if I go back to over here I can easily modify
the title or the body and then if I go to my console log and I'll just log it
to the console real quick just to show you that it is in fact being updated
correctly so hello world is the title
and then welcome to my app is the body
this is the data that we're going to send to the server side now there is obviously
one more field the user ID we
don't have an actual user so we're just going to hard code this so what I'm going
to do now is I'm going to add a
button that's just going to have the text of create post so I'm going to add
that button inside this form element so we'll have the button and we'll just call
this create post and again we've
done this several times already so this should be familiar if you've been following
along with with every section of the tutorial if not that's okay what
I'm going to do is since this button is inside the form itself all we need to do
is just handle the onsubmit event because that is triggered when I click on this
button
itself and we're going to pass the Callback function and then the Callback function
for the onsubmit I'm going to
pass in this argument the event object and we're going to call e. prevent default
this will ensure that the form
when I click on this create post it doesn't cause the browser to do the default
Behavior which is going to
actually refresh the page well it actually tries to send the data to the server but
it does refresh the page okay
and then what I'm going to do when I click on the button is this it's going to call
this function it's going to call
this callback function and we want to send the data to the actual fake Json server
so we're going to make a post
request using the fetch API so similar to what we did in the previous section of
this tutorial where we made a get
request EST but this time we're making a post request so I'll show you how to do
that so first let's do some validation
let's make sure that both title and body are not empty strings because we don't
want to send empty data to the server so
I'll do this if blog poost data. title and blogpost data. body so remember that
a string an empty string is a falsy value so both of these strings need to
be actual it needs to be non empty values for this condition to evaluate the true
okay so if at least one of these strings if they evaluate to a false Val value
okay so in other words if one of them is an empty string this whole condition will
evaluate to false which means that
this whole block of code will not execute and that's what we want we want both
title and body to not be empty okay
so we're only going to make the API call if title and body are not empty so if
that's the case I'm going to go ahead and use the fetch API and what I'm going to
do just to keep things simple I'm
going to actually just use the then and catch syntax to handle everything instead
of just using async
AE so I'm going to do Fetch and then we're going to need to specify the Endo
so that's going to be this URL and then SL posts which is the Endo
right over here so basically this is the base URL and then this is the end point
that we are making the request to SL
posts okay and then we need to make sure that we pass in the second argument
which is going to be our request uh options so we want to make sure we explicitly
set the method to post
because remember by default fetch is going to default to a get request but since
we're making a post request we
need to actually explicitly set that and then we also need to make sure we pass
in our request body and remember that the request body is basically an object
that you are going to be sending well you're not actually sending an object um it
may look like an object service level
but when it goes through the whole network it's actually serialized but in the end
it's actually
going to result into an object okay the way that the server parses it will end up
being an object so you want to always
make sure that you have your request body right over here and what we want to do is
we just want to set the key value
pairs that we want to send to the server so the server is going to expect three
properties in our object it's going to expect the title body and the user ID so the
user ID like I said we're going to
just hardcode this we'll just set it to one and then we are going to go ahead and
set the
title and the body like this okay whoops sorry about this title is going to be
blog post data. tile and then body will be blog post data. body just like that
okay and that should be it so before I do anything with handling the promise
let's actually make sure that the network request is succeeding we can verify that
in the network tab so I'm
going to refresh the page and watch what happens when I type
uh hello world and then hey let's click on create post okay so when you look at
the network tab you can see that a request was made to the server and I know that
this request succeeded because
the status code is green well it's a 2011 status code which is a successful status
code and it's green and 2011
basically means that you created the record successfully okay which is good if you
look at the payload you can see
uh an object was sent if you look at preview uh so right now actually we have
a problem because if you actually look at the payload this is not what it should
look like and the preview of the data it should actually return the
actual entire object with the title in the body that we uh that we sent but
right now it's not actually returning that and you can also confirm this if you
look at the documentation of this uh
mock server that this is actually what it's supposed to return now the reason why
this is happening is because right
over here for our body property it's not actually supposed to be an object it's
supposed to actually be a stringified object itself so the easiest thing that we
can do is we can actually use this
json. stringify method and then just pass in the object itself so what this
will do is this will literally just convert the Json object from an object to an
actual string and that is what we
need to do in order for this API request to properly create the data okay even
though the request succeeded the contents that we send was not correct now I'm
going to go ahead and refresh
the page and I'm going to show you what happens now so let's do Hello World create
post so the request succeed Ed
now notice how this time if I look at the payload you'll see that it says body
title and user ID if I look at preview we have 101 uh not really sure why it
is still uh maybe let's see oh you know what I forgot to add one more thing
perhaps I need to set the content type to application Json maybe that's what it
is so that's good that we caught that so often times when you are making Network
requests the server needs to know how to
interpret data and how to parse the data as well so when you set these headers such
as content type that allows you to
specify okay this is supposed to be Json okay so let's go ahead and just add
this part real quick and let's paste that over here just like this and now we
should not
have any issues we still do need the stringify though so if I go ahead and refresh
let's just type some random
stuff so now yep there we go we have the correct response sent back from the
server we have the correct preview and the payload is perfectly fine and if I were
to remove the stringify part and
just return or just sent this itself okay you can see we get a 500
error code and uh this time I can actually handle that
correctly in the catch block okay so let's go ahead and just handle our our
uh our success and errors so when the response is successful we're going to
get a response back and all I'm going to do is just call response. Json because I
want the
actual Json object that was sent back from the server and I'll just go ahead and
say success and then log the data if there
is an error we'll just go ahead and catch that and then I'll just console log the
error like this okay again a
very basic service level example of how to make a post request now if I go ahead
and refresh the page and if I try to do
this you'll see now we actually are able to properly handle our errors online 33
it is logging syntax error unexpected token s uh so yeah you can see that it is
ering out because of this object over here okay now let's go ahead and just
add that json. stringify call again to this object and we should no longer get that
error you can see now it logs
success and then the actual response from the server when we successfully created
the record so yeah hopefully
this makes sense I don't think if you actually were to call the Post endpoint it
would actually show you um the actual
added post so don't worry about that though it's okay because like I said the
whole purpose of this example is to show you how to actually make a poster request
so now that you know how to do
this when you actually have a real API that you're going to make post request to
you know how to do that you know how
to paste the URL you know how to specify the method request type you know how to
parse the Json object that you want to send into a string by using json. stringify
and then you know about the
headers as well so hopefully this part made sense
Creating Custom Hooks
now before I move on entirely from the use effect hook I did also want to show you
a couple of other examples and some
other patterns that you can use the user effect hook for so as I mentioned earlier
whenever you register event
handlers directly on the document itself that is also another known example of
performing a side effect and it's not
not that it's a bad thing because oftentimes you will need to do that so an example
would be if you need to detect when the user is resizing their
viewport their browser then you may want to perform some kind of action I'll show
you how to do that using a use effect hook so what I'm going to do is I'm
going to go ahead and call use effect and then pass my callback function and I only
want to have this callback function
executed one time and it would make sense because we only want to register the
event listener once on the document
it wouldn't make sense for us to register multiple times because there's just no
need to so what I'm going to do
is I'm going to use an empty dependency array this will ensure that my call back
executes one time only no matter how many times we update our state if there
is any state if we update it it's not going to cause this call back to execute
again and I showed you that in earlier
examples of the use effect H so what I'm going to do is I'm going to add an event
listener on the window object I'm going
to do window. addevent listener and there are a bunch of events that you can
register directly onto the window itself the one I'm going to do is let's do
resize so this will of course occur whenever you resize the browser window
and what I want to do is I could pass in the Callback function this is known as a
listener function because it literally
listens to the event and it's going to be what is used to handle the events
whenever it happens okay so instead of actually just passing the Callback function
like this I'm actually going to
go ahead and create a function a named function specifically so I'm going to go
ahead and call this resize event handler just to be more verbose with my variable
names and then I'm going to go ahead and pass it like this now the resize event
handler does take in an argument you can
even see that in intell sentor right over here if I do this you can see that the
event itself is a UI event
so we're going to go ahead and do e and I'll just go ahead and console log
window viewport resized okay and I'm
going to go ahead and go into my browser now and I'm going to show you what this
looks like so
let's refresh the page notice how if I change the size of my viewport you can
see that it says window SL viewport resize which implies that this resize event
handler function
is in fact being called every single time it detects a resize of the viewport
of course if I were to let me do this let me kind of uh resize the browser
itself I mean resizing the browser is going to cause the view port to resize so
it's going to trigger the event
regardless we can see that the view is changing and then that event is being
triggered okay now what we want to do is whenever the
component unmounts because it could possibly unmount we want to make sure that we
are unregistering this event
from the window itself because if we don't do that and the and the component
unmounts what's going to happen is that if the component mounts again which could
possibly happen especially if
you're performing something like a conditional render it's going to cause a another
event of the same instance to be
registered again so in other words when the app component remount your resize
event is going to be registered again and again and again okay so to avoid
registering the same event multiple times what we want to do is we want to use the
cleanup function inside our use
effect callback now this is something that I did show you earlier when we first
talked about use effect hooks but
in case if you missed that the cleanup function is basically this function that you
can return inside the call back
itself so it looks like this return and then this function right over here and
this is your cleanup function this function is called whenever your component
unmounts okay which happens whenever the component no longer needs to be rendered
anymore no longer needs to be in the document anymore so it will just unmount from
the document and then if you need to render the component again based on
some kind of condition or for whatever reason then it will basically Mount
itself and then call the use effect hook at least once okay so what I'm going to
do is I'm going to go ahead and call window. remove event listener and I want
to specify the event that I want to remove that I no longer want to listen to and
that's going to be the same event
resize whoops right over here and here's the thing though as the second argument
we need to pass in The Listener function which is resize event handler right over
here this is very important because if you don't pass in this call back you're not
going to actually remove this event
from being listened to in the documents okay so it's very important and the other
reason why I did not use an
anonymous function like the other reason why I didn't do this is because you
actually need a reference to the
function itself so that way we know which specific event and which function
that handles that event to actually entirely remove it from if you use an anonymous
function there's no way that
you can actually know which function is handling that event and also it's not going
to actually remove the event
listener from the document itself or from the window in this case so that's why we
need a named function so we have
reference to it okay so now what's going to happen is it's going to remove this
event listener uh so let's do this let me go ahead and refresh the page so
obviously right now it's still going to work um let's see what I can
do uh you know what maybe what I can do is I can actually move this into a
different component so let me do this just to show you an example okay so what I'm
going to
do is I'm going to take this whole thing I'm going to cut it I'm going to paste
this inside just any component I'll use the login form as an example okay any
component will work fine you don't have to use the login form component you can use
any component I'm going to conditionally render the login form
component based on a state variable so I'll do a
toggle variable so it's going to be toggled between true and false and then
I'll have a button that will allow me to update the state of toggle each time so
whenever I click on the button
it's going to toggle between false or true true to false so basically I'm going to
call set toggle and then I'm
basically just going to update the state to the opposite value cuz there's only two
possible values true or
false and then what I'm going to do is this whenever the button
is uh true I'm sorry whenever the toggle variable whenever the value is true
we're going to render login form just like this okay and the whole purpose of
this is I want to show you the login form component unmounting and I will add a
console log inside this cleanup
function unmounting login form and then I'll also add another log
removing resize events listener okay so whenever toggle is true
we're going to render login form login form will render and it's going to go ahead
and call this us call back one
time and one time only because we have our dependency array set to empty so
even if State changes inside login form this will not call the call back again
unless if we added that state variable
to this dependency rate that's how it works so now let's go ahead and test this
whole thing out we're going to go
into my browser and in my Dev tools I'm going to go to elements and then event
listeners right over here and I'm going
to show you to verify the event being registered and unregistered so I'm going
to refresh the Page by default right now the resize event listeners not being
listened to because remember that we are only registering ing it when the login
form is rendered to the document and currently we're not rendering it because
toggle is set to false because we're
doing a conditional render now I'm going to go ahead and click this toggle button
which will update the state of toggle to
true and that will cause the login form to render which will then cause this use
effects call back to be invoked so let's go ahead click
toggle now you can see right now if you look at the logs it does say unmounting
login form and then removing resize
event listener remember that we're in strict mode so your component your use effect
hook it's going to be invoked
twice okay so it renders the component unmounts it and then it renders it again
okay so that's the reason why you only see this cleanup function being invoked one
time hence why it logs these two
messages one time only okay the second time it renders the component but it does
not unmount so the cleanup function
is not called remember the cleanup function is only called when the component
unmounts from the document
okay so I clicked on the toggle button and I can see the login form now I'm going
to go over here to event listeners
and I'm going to click this reload button or refresh event listeners because we did
in fact add an event
listener but it's just that this thing needs to be refreshed to see it so you can
see now right over here I can
clearly see that this resize event appears and it's on the window and you
can see the Handler and I'm not sure if you can probably see the implementation
probably not but it
does tell you that this event is in fact being registered you can see resize is
right over here and it's on the window itself okay that's awesome now of course
to verify even more I can resize the window and you can see windowview Port resize
is being logged which is what we
have uh being called whenever we resize the window itself okay now what I'm
going to do now is I'm going to click toggle again that will update the state of
toggle to false which will then
remove the login form from the document because remember we are conditionally
rendering this component and since
toggle is false login form will not be rendered so the component will be unmounted
so Watch What Happens I'm
going to click toggle now you can see that unmounting login form and removing
resize event listener was logged to the
console which implies that our cleanup function inside this use effect in our login
form component is being called so
window. remove event listener is being called as well okay and to verify if I
refresh this event listener section you'll see that we no longer see the resize
event appearing over here and I
can further verify if I resize the browser the window you can see that the
windows viewport resize is not being logged this was from previous but I'm I'm
going to go and clear the console
and I'm going to resize and you can see it's not being logged at all if I click
toggle again refresh this I can verify
the resize event was in fact registered and I can resize the viewport and I can
see that that call back function is being invoked and it's calling the console log
and it's logging this
message to the console so I hope this makes sense because it's important to
understand that whenever you register an
event listener you need to know when exactly you want to unregister it and a good
time to unregister it is when it's
no longer needed and that really just depends on your application needs in my
situation I don't need it if the login
form is not rendered to the document so I'm going to unregister it by calling
window. remove event listener inside the
cleanup function okay now obviously you can register whatever events you want so if
you want to register an event on the
document you can so document. addevent listener there are a bunch of other events
let's do a click click event
right and let's go ahead and add a callback function let's call this handle
document click so this will basically be triggered whenever we click anywhere in
the
document let's just do click documents okay and then now I'm going to
just duplicate this part but instead it's just going to be document. remove event
listener and it's just going to be click
and then we're going to go Ahad and pass the same Handler that we used to register
the click event on the document
so handle document click and now I'm going to go ahead and refresh if I click
toggle and I refresh you'll see now we have uh
resize and we also have click which is on the document itself now I can click
anywhere and you can see whenever I click on anywhere in the document it's going to
go ahead and log click document
okay if I click toggle you're going to go ahead and see that when I click again the
logs do not
log clicked document because the event was
unregistered if I refresh you can see that click is no longer there same thing with
resize so I hope that this makes
sense because it's very important to understand how to properly register and
unregister events from your document or
really anything okay any HTML element now there is one more thing that
I do want to show you and that's how to write custom hooks in react so far we've
used two hooks we've used the usate hook and we've also used the use effect hook
there are often times where you want to create your own custom hooks because you
might have let's say for example a use
effect hook that has a bunch of reusable logic that you may want to reuse in other
components as well I'm going to
show you how to do that right now it's actually very simple so what I like to do is
I like to create a new folder
and typically I call this utils and inside the utils folder I create a folder
called Hooks and this is where
all of my custom hooks will go so hooks have a convention whatever the name of
your hook is you want to always prefix it with the use prefix so for example
let's say my hook the responsibility of my hook is supposed to register an event
listener on the document whenever I click on the whenever I click on anywhere in
the document right so I'm
going to go ahead and name my hook you use document click or you can call it use
click documents okay and we're going
to do do jsx we're actually it's going we can actually just do JS because inside
this
use effect we're not actually um returning any jsx at all or it's just
all going to be just plain JavaScript so now this function is going to look like
this function use document click we also
want to make sure we are exporting it so I'll do that export ort function use
document click and then what I'm going to do is this I'm going to go ahead and
inside
this function I'm going to go ahead and call the use effect hook and I'm going to
go ahead and
register The Click events inside this use effect hook okay
so we're going to do document. add event listener click and it's basically going
to look exactly like what we did inside this use effect okay so I'm going to copy
this handle document click all back
and I'll just I can actually just put it up top over here and then uh what I'll do
is
actually you know what I I'm going to put it inside the use effect and what I'll do
is I'll just pass it right over
here and then we also want to make sure we have our cleanup function to take care
of unregistering the events so
return and I'm going to go ahead and do documents. remove event
listener click and then handle document click okay and so now what I can do is
anywhere in my application I can use this custom used document click hook
okay so the way it's going to look like is this first let me remove all of this
stuff over
here and let me remove this okay so what I'm going to do is I'm going to go ahead
inside my login form so right underneath this use effect hook I'm going to go ahead
and call use
document click just like this okay and now if I go to
the browser well actually you know what let me do this I'm going to write a console
log use document click so let me go ahead and refresh the
page so remember that our login form is being conditionally rendered so by
default it's not going to go ahead and uh execute any of these hooks or any of
the logic here so let's click toggle so that will cause our login form to be
rendered and now you can see that use document click is being logged to the
console which implies that our Hook is properly being invoked okay and also one
more thing let me add an empty array over here because I only want this hook to uh
register one time or I only want
this hook to be called one time the Callback function and then I only want the
event
to be registered once okay so let's refresh click toggle now I can see that again
because we're in strict mode it's
going to go ahead and invoke that callback function twice because the component
renders two times that's okay
because we are also unmounting the component after the first render and we are
properly handling the removal of the
event listener okay so in the end our event is only registered once so you can
see over here that uh we have use document click log twice after the first
time it's unmounted so it calls uh this call back again and then you can see use
document click is logged so anywhere I click it's going to go ahead and just
trigger this events okay so this is an
example of how you can create custom hooks you can do the same thing with literally
any use hook or even if you
are creating a custom hook that defines some State and have it returning those
State you can also do it as well okay so
this is just a very simple example of how to create a custom hook okay so I
hope this part makes sense
React Context
in this section of our react tutorial I want to teach you about the react context
API the best way to understand
the context API and the purpose of it is to understand a problem that you will run
into so let's say for example I have
these three components that I just created from scratch very simple components okay
I have a post container
component and this is typically a wrapper component that contains all of
the posts that you would want to display to the user to see such as social media
posts as an example right it's supposed
to display a list of posts but just for Simplicity I'm only rendering one instance
of the post content component
now post content is a child component of post container and post content has its
own child components as well such as this post content buttons component in this
case it only has one but it could
have more than one and then the post content buttons component currently has
nothing but down
the road as your application grows you may render other elements or components
in this component as well so if you think of it like this if you think of it in a
tree hierarchy you have post
container post content and then post content button and then of course we may
render post container in a root component such as the app component itself so that
would create a hierarchy
of four layers now that's not a problem but think of it like this let's say for
example down the road we may have to pass some props from post container down
to post content and then allow post content to use those props to
serve data to the user render it to the document whatever and then maybe those
props will also need to be passed down to post content buttons as well and then
maybe if post content buttons have its own child components it needs to pass those
props as well so I'll show you an
example where I have some props so I'll Define some state right now I'll just call
this data just simple
example hello world just simple string and then I need to pass data down to
post content so I'll just call the prop data and then post content needs this
prop and then we need to pass data down to post content
buttons okay and then let me go ahead and take that data in and I'll finally
render it inside this component okay we're not going to do the
prop validation I'm just going to show you a simple example I'm going to go ahead
and render post container in my
app component so we can actually see it in the document in our website there you go
you can see that
this hello world text is being rendered from this post content buttons
component okay and of course if I remove this it disappears so if you notice right
now I
have to pass this state variable as a prop down to post content and then I
have to pass from post content down to post content buttons okay so I have to
pass the prop two times now it could be more complicated I may have let's say 10
other child components that are in its own layer in the hierarchy so for example
post content buttons may have
other child components it needs to render and then we need to pass data down to
those child
components okay and we don't know how many times we have to pass that prop
down until we can finally actually display to the document or do something with it
and this becomes a problem when
you have a very large code base when you have a bunch of different components
because it becomes very unproductive
having to go through a bunch of different files and just drilling the prop down
each layer over and over again
this is known as prop Drilling and then if something changes in your
application let's say you no longer need the prop anymore well you're going to have
to go through each component and
remove that prop from the function signature over here from
the arguments section right and you're going to have to remove it right over here
and then it's just a bunch of
unnecessary work that you have to worry about especially if you have a very large
Cod imagine you have to pass your prop 10 times and then if you no longer
need that prop down the road you're going to have to go through 10 different files
just to remove that prop and then make a PLL request and then deploy that
change to production becomes a headache so this is where the react context API
allows you to avoid this problem so think of the react context like this
instead of having my data right over here inside post
container and then having it passed down to post content and then passed from
post content to its child components what I can do is I can actually have my
data my state set inside the context itself and
I want you to think of like this the cont context itself is literally just an
object okay and it's separate from the
component level itself the context can hold information
that can be accessible from any component that is within the
context okay and again it's hard to kind of like understand how that works just
from a verbal example and that's why I'm going to show you in code how this is
structured okay but basically the
context itself allows you to store information and then as long as your
components are within the context if they're wrapped inside the context known as a
context provider those components
can access that data anywhere they want without needing to have it passed as a
prop okay so for example post content buttons I am in the third hierarchy or
in the third layer of the hierarchy or actually it's the fourth layer assuming that
we're starting from the app
component instead of just having our data passed down all the way to this
component as a prop I can easily just reference the context and grab that data from
the context okay and again the
context is literally just an object that contains information that you can
reference from within anywhere you want
as long as you're inside that context okay so now let's go ahead and actually set
up a context in react so
you better understand how this works and so that you can create more scalable code
bases for your react project so
Creating a Context
what we're going to do is this I'm going to go ahead and inside my utils folder
I'm going to create a new folder called contexts you may have as many contexts as
you want because different contexts
can represent different things so I'm going to go ahead and create a new file and
I'm going to go ahead and call this
user context because this context is going to pertain to user data and I'm
going to name the file with a JS extension because we're not dealing with any jsx
at all okay so the way that
we're going to create our context is first we need to import the create context
function from react this is a
function that allows you to literally create a context so what I'm going to do is
I'm
going to declare a variable and I'm going to call it user context capital u okay
equals create
context just like this and then all you do now is as an argument to the create
context function you just pass in any default value this can be a string this can
be a number Boolean object array
anything you want okay now you don't actually have to pass in any specific
value because these values are going to get overridden when you actually set the
values when we use what is called a
contact provider but all you need to do is just shape your data over here so since
I'm
dealing with with the user what I'll do uh is this I'll go ahead and just
have the ID be uh I guess actually I'll set it to zero since I want my ID to be
numeric value username I'll let that be an empty string email empty string and
then display name empty string this can be anything you want okay it doesn't really
matter what you have set over
here now I'm going to also want to make sure I am exporting this user Contex
variable as a named export because I will need to reference this context later on
and we're done with this file
so now what I can do is I can go into my app.jsx file okay and I can import the
user context from the utils context user
context file and then what I want to do is I want to use the user context
provider okay so one thing that I should also mention is that the user context
itself is an object and you have these three values you have the consumer provider
and the display name we want to
use the provider itself because we want to use the provider to wrap all of our
components that we are providing data for that's literally why they call it a
provider okay so the way that we're going to do that is like this so remember that
our app compon component
is our root component okay so every single component will eventually be part
of app okay well I mean it actually is going to be part of app so what I'm going to
do is I'm going to just copy
this div and just remove it I'm going to cut it and I'm going to reference user
Using Context Provider
context with angle brackets like it's an actual component or HTML element and I'm
going to reference provider and then
you're going to it's kind of like you're rendering it okay but in reality you're
actually just using the provider this is
how you use it okay and then you're going to paste your component or your
jsx elements whatever it is inside the provider itself okay so now what this
does is inside my provider I have my post container component so any
component that is within this provider or any component that is now inside the
post container child components of it are now part of the user context that's
what that means okay so we are wrapping the user context provider within this
whole section over here which means that any data that we have set on the user
context will be accessible in any component from within so the post
container component can access the data of user context so it can access the ID
username email or display name and then
child components of post container such as post content as well as post content
button because remember post content button is a child of post content which is
also a child of post container okay
so all of those components are within the context so they can access that data
without needing to have it pass as a prop and you'll see that in just a second so
before I do anything else I'm
Consuming Context
going to show you how we can actually access data so I'm going to go into post
container and I'm going to go ahead and use a hook called use
context I'm going to call this use context hook and now you can see that it expects
an argument a context argument
and that is going to be this user context object right over here that was
created when we called create context that's why we needed to export it because we
need to reuse it so I'm going
to go ahead and pass in user context as an argument and this is known as consuming
the context okay when you call
the use context hook and pass in the context you want to consume it returns an
object with the data that you had set well actually it would return the data
that you set as a default value itself over here so since this is an object right
over here when I reference it I
can reference all the fields but if I set this to be a literal value like a number
number then the return value of
this would be a number as you can see over here the return value is a number and I
can no longer reference those fields okay these methods are the
methods on the number itself so hopefully that part makes sense so what I can do
now is I can
assign this return value to a variable so I'll just call this user context data
just to be verbose and what I can do in this post container component is I can
reference
all of the fields on this user context data object and I can render it I can send
it to an API server I can do
whatever I want with it now right now if I try to reference these fields and try
to render it it actually won't do anything and the reason why is because
I'll even show you right now you'll see that if I actually go to
the document and if I show you the dev tools you'll see that right now we're
getting this issue that says not read
properties of undefined so right over here even though we do
have this default value set when we pass the object into the create context call
it doesn't actually set the data for you because we need to actually set it at
the provider layer over here okay so that's the reason why we're getting this error
right over here when I try to
reference display name as you can see it's giving us this error over here when I
try to reference it okay what we need
to do is we need to go back to our app component and then where we are invoking
this provider there is this prop that I can pass called the value and this is going
to allow you to
pass data that pertains to what you have shaped in your create context over here
okay so what I can do is I can set the ID so I'll set it to one I can set the
username whatever key value pairs you set in this object is going to show up in
intellisense over here okay so
username I'll just do an the dev email anev
gmail.com and then uh display name Anon the developer developer now if I go back
over here let's go ahead and try to reference user context data do display
name and I'll render it to the document you'll now see that the display name that I
had
set right over here in the value object okay that is now being displayed in the
document so let's kind of just recap what is going on okay so what I did just now
was I passed in my object that is
based on my user context default value right over here so I passed in an ID
username email display name as fields in this object and when I consume the user
context all of that information is stored into this user context data
itself I can even consol log this whole object to show you what it looks like
and you'll see that all of the values that I set are over here and those
values are coming from this object literal right over here that I passed in
when I invoke the provider okay so I can go to any
component as long as it's within this provider's context and consume the context
itself
and reference the data so what I can do now is let's go into post content and let's
do the same
thing so what I'll do is I will declare a variable called user context data and
then I'll call use context and then pass user context so we're consuming the user
context And all I'll just do is I'll just render the how about I'll render
the email this time in post content so now you can see that the email address
is being rendered right up top over here okay it's being rendered over here and
now I'll go into my post content buttons component and I'll do the same exact
thing thing I will go ahead and declare variable user context data and then call
the user or call use context and pass in user context and then what I'll do I'll
remove this data prop because we no longer need it anymore and this time how about
I'll render the
ID and now you'll see that the ID is being rendered to the document okay so
you see how anywhere in my components in my component
hierarchy I can access the data that is from the context so I don't need to
actually pass this information as a prop anymore because I can store it in the
context and then I can access it from anywhere I want as long as we are within
the context okay hopefully that makes sense now I want to show you this one
thing let's say for example uh let me remove post content
buttons from post content so we're not going to render this component inside post
content going going to remove that
for now and then what I'm going to do is
this I am going to go into my app component and why don't I do this why
don't I uh cut this and use a fragment so I can render this and then I'm going to
go
ahead and render the post content buttons component like this so I'm rendering
these two within a fragment okay and in post content buttons we're
trying to consume the context and reference the ID now let's see what
happens because notice how now the post content buttons is no longer inside the
user context provider it's outside of it so we shouldn't be able to actually
access this data over here let's see what happens so if I look at the
document Let me refresh if I look at the document right now so you can see that we
have our post container being
rendered is currently rendering the display name right over here and then
the post content is rendering the email which is right over here and then right
underneath we have our post content buttons which is rendering the
ID right over here and notice how the ID is zero and that data is
actually coming from this default value right over here so even though we can
actually still access the default value we don't actually get the the updated
data that we set in the provider itself so while we can access the quote unquote
the default value the information that we are passing to the provider as a value so
the ID username email display name is what is important okay where we can we
cannot access that actual data because we are outside of the context itself
okay now you're probably wondering well why is this important because it may not
seem like it's a big deal right now but
keep in mind that we are currently passing an object literal to our
provider's value but what I'm going to show you in the next example is how we can
actually
create a state variable and then I'm going to pass that state variable as the
value to my provider that state variable is going to be an object that represents
all these key value Pairs and
then I'm going to show you how we can actually make updates to the data that is in
the context itself because
obviously over time we may want to make updates to our data that is stored in
the context cuz that's just normal for any application okay and then you're going
to see how that when I make changes to the data I want that information to be
reflected
anywhere else within the provider within the context that is consuming that data so
that way the latest information is
being displayed so this is kind of like a preview right now because you can see
that although I am outside of the
context and even though I can still access the default value even if I make updates
to the
context right now because this component is outside of the context it will not be
able to
access the latest value hopefully this makes sense now what I'm going to do now
Using State with Context
is I'm going to go back to my app component and instead of just passing
this object literal this hardcoded object right over here we're going to go ahead
and Define some states so I'm
going to go ahead and call this user data set user data because right now we
don't have any actual way to update the content text Data this is all hardcoded
we want to be able to update the data for the context itself so typically in a
realistic application what you would do is in the component that you are actually
invoking the context provider
you actually Define your state variable that pertains to the context data itself
so since my user context is an object that represents the user itself it has
the ID username email and display name I want to create a state object that
represents that as well because now I have the state object as well as the dispatch
function and we're going to
actually use this that dispatch function to update the state itself so we're
going to need to pass that dispatch function uh into the context so that way
those components can access that function you'll you'll see what I mean in just a
second so watch this I'm going
to go ahead and for now I'm going to set all of these fields so ID username email
and display name in this initial State object over here okay and again it's
going to look like it's hardcoded which it is but typically in a realistic scenario
you actually fetch this data
from an API and then you call your dispatch function to update the user data and
then that data would be
actually passed into the provider's value and then your other components consuming
the context would have access
to it I'll actually show you another example where we fetch an API to get the
data and you'll see how that works so that way you have a bunch of different
examples to work with so don't worry so
what I'm going to do is I'm going to pass user data right over here okay and
let's just verify that everything else is still the same so you can see that we
still have our email our display name
and then our our buttons component over here is still displaying the default value
of zero I will go ahead and remove
this and go back to post content and render post content buttons okay
whoops here we go and just to confirm if I go into this initial State object if I
change any of these values it's going to go ahead and reflect in those components
we're not rendering the
username yet okay there we go right over here okay so what I'm going to do now is
I'm going to go back to my user context and I need to modify this because right
now our context only has key value pairs that are all literal values we don't
have a key value pair that pertains to our dispatch function we need to
basically set a value that represents our dispatch
function so that way when we consume the context we can reference that dispatch
function and invoke it to make updates
to our state so you can call it whatever you want I'm going to go ahead and just
call this uh set user data the same thing that is named after this dispatch
function over here inside my create context object right over here and the
value of this is just going to be this function over here that does nothing and
since we're using JavaScript you don't have to worry about passing specific
arguments and type annotating anything
if you are using typescript you may have to do that but I assume you're not using
typescript obviously because you're
following along with this tutorial in JavaScript but I do want to mention that in
case in the future you do choose to use typescript to keep that in mind so
so set user data is going to be a function that returns void that's fine
and remember that the the data that you set in this object doesn't matter because
it's going to be overridden
when you pass it as a value to the provider keep that in mind okay so what I'm
going to do now is I'm actually
going to go ahead and use the spreader operator to just pass in user data like
this so it's essentially creating a copy of user data but then this will allow me
to actually set the set user data
property and pass in the dispatch function into this value over here okay
so I could do it like this but since the name of the field is the same name as the
uh dispatch function name itself I
can actually just do it like this so now anywhere my components you can see
that right over here if I reference the user context data I actually can reference
this set user data property
and although it is showing up as an actual field and a of function I can actually
still invoke this just to keep
just keep that in mind okay so when me show you right now if I go to the
console you'll see right over here that in the user context object I have set
user data and the data type is a function okay function that returns void to be
more specific so what I can do now
is anywhere in my component that is inside the user context I can invoke
that set user data function to make an update to the user data State
okay so watch this I'm going to go into post content
buttons and I'll just go ahead and simply add a simple
button again this is just just to show you a simple example okay nothing fancy so
what I'm going to do is I'm
going to add a click event listener and when we click on this button what I want to
do is I want to call user context
data or I'm sorry I want to call the set user data function that is on the user
context data object and I can actually just destructure set user data from this
whole object like
this and what I can do let me also destructure the idea as
Updating Values in Context
well and what I can do is I can call set user data like a regular function because
it is a function and I can
update the state so whatever it is that I want to update I can update literally
anything I want that pertains to my user
data State itself so I can update the ID the username email display name whatever
it is okay so just to show you an example I'll just update the display name so what
I'll do is I'm going to go
ahead and pass in that callback function because remember this is our dispatch
function so it is going to allow us to
take in our our callback function and that argument in that callback function gives
me access to the current
state and then I want to basically create a copy of the current state and
then only set the display name to my new value so
I'll just set this to uh I'll just literally name it updated display name
okay and then now let's just see where are we rendering display name we are
rendering it in post container
so this is what I'm going to do uh let me do this let me kind of label everything
so I
know what is
what let me just do that real quick okay so this is post container and then I'm
going to do this post content and then let me go
inside here and then let me label this as post content buttons just so that way
we know what component is what so so that way we we're not just seeing a bunch of
data not knowing where it's
located okay so what I'm going to do now is I'm going to refresh the page and now
you can see right over here we have post container and post container renders the
display name so I'm inside the post content buttons right over here remember
this click me button is inside the post content buttons okay we just implemented
this button and then the the unclick logic over here when I click on this button
it's going to go ahead and update
the state of user data so that's going to basically update this state right over
here and this state is at our app
level which is in the same level where we are using our context provider okay
so we're basically updating this user data the display name is going to be updated
when it is updated keep in mind
that we're still updating state so our app component is going to actually render
and when it rerenders it's going
to pass in the new values to the user context provider so the new value will
be whatever it is that I set to display name because that's what I'm updating okay
so watch what happens when I click
on the click me button did you see what happened when I clicked on that button
the display name was updated okay it went from an and the developer to
updated display name of course this can be whatever you want you can even add in an
input field to type whatever you want
so I really hope this makes sense and this shows you how literally anywhere in
your application you can modify your data that is in the context the single
source of truth and you never have to really worry about what component has
ownership of what state or what props all we need to know is that we have our
data stored in one single place and then as long as we're inside our cont context
we can access that data and then as long as we give an appropriate function to
update that data we can do that from wherever we want inside our context
Custom Data Fetching Hook
okay so as I promised I wanted to show you an example where we can fetch data
from an API set that data at the state level and then have it passed down to
our provider for our context so let's see here's what I'm going to do I'm
going to go ahead and use the same Json placeholder API server that I was using
in previous examples and let's do this uh do they have an endpoint to get just one
user maybe not so I think what I'll do is I'll just fetch this data and I'll
just hardcode it to use the first element in this users array that should
be fine for a very basic example I think actually if I do user SL1 Yep this would
give me the
individual user itself there we go okay so let's do that instead so again we're
kind of combining all of the previous previous uh things that we've learned with
data fetching and updating State
all together in one single example okay and again this is a
realistic example as well because in a realistic application you'll find yourself
of doing things like this okay
so here's what we're going to do and I'll make this very interesting so we need to
fetch the data
from this API endpoint and we want to perform this side effect inside our use
effect hook so you might be tempted to First implement this use effect hook right
over here but how about I do this
instead let's go ahead and write a custom use effect hook that calls this
user's endpoint to get the user self so let's go into our fix folder and let's
create a new file and I'll call this use uh fetch user okay.
JS and then we'll export this function and we'll call it use fetch
user okay and this function is going to take in one argument we're going to make
this a dynamic hook because remember how we can pass in any ID of the user and
get a different user so if I pass in two or three I get a different user every
single time so let's go back to our code
so we'll just call this argument ID or let me do user ID just to be more
specific okay so in our custom hook remember that our Hook is literally just
a function and in this hook itself we can actually use other hooks so for example I
can use the use effect hook
and if you missed this example where I showed you how to create this custom use
document click hook you'll
recall that we did in fact call the use effect hook inside our custom hook okay
so we're going to use the use effect hook and then what I'm going to do is I'm
going to make an API call so we're
going to use the fetch API and we're going to go ahead and get this URL right
over here and let me go ahead and do this let me set the URL
to this okay because I want to make this a little bit more Dynamic so we're going
to use a template string to reference user API URL and then we're going to
have to add that forward slash and then we're going to use a template string uh
within the same template string we're
going to uh evaluate the user ID variable okay so this whole thing pretty
much evaluates this user API URL it adds the forward slash and then it
adds the user ID right over here so this kind of like builds out the entire API
URL endpoint without having to hardcode it okay so we're going to fetch this URL
and since this is a get request it we don't have to pass in any additional
arguments any additional options it just
defaults to a get request we don't need to passing any headers or or nothing so we
can leave it like this but what we
want to do now is is we want to handle the API call because remember fetch
returns a promise so what I want to do is this I want to go ahead and use then
I'm going to get the response and remember we're going to have to call response.
Json to get the
actual user data okay so this itself returns a promise and what I can do is I
can just return uh this response. Json call inside this dens callback function
okay and what that allows me to do is that allows me to handle that Promise by
calling then again and then this
time this callback function inside this second. then gives me the actual data
itself okay I'll console log it very quickly just to show you what it looks like
and when there's an error we'll go
ahead and just catch the error and then I'll log it just tempor arily but there's
another thing that I want to show you what I want to do okay so let's
go ahead and also add a dependency array and for the dependency array I'm going
to go ahead and add the user ID as the dependency now I know that the
user ID is not going to change at least in our implementation we won't have it
change because we're going to have it
hardcoded but just do know that if your user ID does change this use effect call
back will run again okay this is something that we discussed in the section when we
covered the use effect
hook okay we're going to we're going to add some more stuff to this callback but I
just want to show you how this works
okay so what I'm going to do is this I'm going to go ahead and
just make sure that this API call succeeds so we're not doing a bunch of things all
at once and then if something
wrong happens it's just going to be a nightmare to debug so we're going to to take
everything step by step so let's
first go ahead and call use fetch user so use fetch user and we're just going
to pass in our ID so just pass in one and now we if we go back to our
application let's refresh the page let's go to the network Tab and confirm you
can see right over here that the API call is happening okay it is fetching the user
with the idea of one and you can see that this is the data that we get back from
the server okay if I were to
replace one with two it would now fetch the user with the
IDE of two okay so our API call is working 100%
in our hook but we're not quite done with this custom hook just yet because
we need to actually get the data from this API I call in order for us to actually
set the data at our state level
over here and then have that data passed into the context provider so what I'm
going to do is
this remember that inside our custom hook we can call other hooks okay and I
can also call the UST State hook so I'm going to go ahead and call the UST State
hook and I'm just going to set the
initial value to an empty object and then for the state variable I'll just call
this user data set user data okay and
then basically what I want to do is when my API call is successful and
when the response. Json call is successful which it should be in this case then
inside this second callback
function for the then call so inside over here we're going to go ahead and update
the state of user data by calling
set user data and then passing in data like this okay now like I said before as
a beginner in react this is the common approach on how you would fetch data from an
API and then update your state
variable when you become more intermediate and when you use a data fetching library
with a library such as
react query you never have to really worry about this but it is also important to
understand how to properly
fetch data and update State accordingly okay so this is what we want to do so
we're going to call set user data and then update the state of user data right over
here okay it's pretty much
it and I'm going to go ahead and just remove all of this to just tight it up a
little bit so now what I'm going to
do is this in my custom hook remember that your hook is literally just something
that can perform other side
effects it can also return data as well okay so what I can do is I can return my
user data so I can return user data just like this and then if you actually go to
your app component where you're calling use fetch user you'll see
that uh if I assign data let me let me just call this
user for now if I assign this to user and if I console log
user you'll see that if I go to the
console you'll see that online 10 that it is logging the user that was
fetched from the API so that user that we fetched from the API we took that
user object and then we set it to the
user data State variable and then we returned it and then that is assigned to this
user variable and when we logged it
this is the result right over here in the console okay so hopefully that makes
sense now I'm going to go ahead and add
some more things to this hook because we might as well do that because I Tau you
about that in the previous couple of
sections just to make this a little bit more uh efficient so what I'm going to do
is I'm also going to add the abort
controller and this was something that I showed you when we first talked about
Network requests so we're going to
create an instance of aort controller and then all I'm going to to do is as a
second argument to the fetch
call I'm going to pass in this signal property and set it to controller.
signal and then we're going to add the cleanup function for this use effect
hook and then we're going to go ahead and just simply call controller.
abort so this will ensure that if we no longer need to make the API request we
actually cancel it okay um and then there's one more thing
that I did also want to do as well that I didn't show you in the previous example
I'm going to go ahead and add
another state variable and I'm going to call this loading set
loading equals use State and this will be a Boolean value and this state
variable is going to track the status of the API call so whether the API is still
fetching or if it has successfully returned or if it failed okay okay so
basically this state variable represents if we are still waiting for a response
from the server so what I can do is the
moment that the moment that this call back is invoked it's going to go ahead and
call this fetch function right so I
can go ahead and call set loading to true and then once I am done with my API
call I can set loading to false so I the best thing that I can do is I can actually
call finally remember that
there's a finally uh method as well and this will be called After the Promise is
pretty much done whether it failed or if it succeeded so I can just do
this finally whoops finally and then I'll just do set loading to
false okay so even if we go into the catch Block in the event of an error
it's going to still call finally okay so the loading the load
variable it transitions from false to true to false during the life cycle of the
API call okay hopefully that makes
sense and I can also do the same thing inside this cleanup function just to be safe
is set loading to false because we're no longer actually making the API
call anymore so the loading variable should be false okay uh and then also I
can return uh loading from this use fetch user hook as well so this will
require me to actually return an object with all of the data so I'll just do return
user user data and then loading like this and another thing that I can do is
I can also uh track the error object as well
whoops so I'm going to go ahead and create a state variable for
error use States and we'll just do we'll just leave it as undefined
and then what I'll do is if there is an error I'll just call set error inside the
catch block and I'll just set the
error object right over here now again keep in mind that um if the fetch API
returns a 404 it's not going to actually error out but if there is a issue with
the API call such as returning a 500 as an example or 401 then it will error out
okay so let's go ahead set the error object here and I think that should be
it and then we'll also return the error object as well now some of you may not
know this but all of the stuff that I'm doing right over here is actually kind of
like how a lot of these data fetching
libraries work underneath the hood so for example react query gives you the data
the loading status as well as the
error object and a bunch of other different things that allow you to enhance your
data fetching okay this is
just kind of like a surface level example of how you can create an efficient way to
fetch data okay so we
are fetching the data if we need to cancel it we cancel it we track the state of
loading and then we also track
the error object if there is an error okay so now what I'm going to do is I'm
going to go back to my app component and I know we kind of went a little bit too
far with this example but again I want
to show you a bunch of different things when it comes to um this example because I
don't want to
leave anything out okay so what I'm going to do is I'm going to go ahead and
destructure the user loading an error and then I want to actually cons
log all of this stuff right over here so watch this user loading error okay and
if I refresh the page you're going to go ahead and see
that right over [Music] here okay uh right over here on line 10
we are logging the user right over here we're logging false
for loading because we're no longer loading anymore we're not we're no longer in
that status and then we're
also logging error which it seems like there is an error in this situation it says
the user aborted a request I think
that has to do with the fact that it is rendering twice so that may be why that is
yeah that may like that may likely be
the reason why because uh when we aborted the request it set the error but we no
longer actually cleared the error
so let me actually do that real quick let me actually clear the error upon success
because we actually should not
have any errors at all so errors should actually be
undefined okay there we go okay so right over here you can see that we have the
user object we have the loading status
false and then we have undefined for the error okay when it first tried to make
the API call yes that's fine that there is an error because the request was aborted
and remember that happens
because we are trying to perform two renders because we're in strict mode so the
first time the component unmounts
which will abort the request but the second time it renders it doesn't unmount from
the document so it doesn't
abort the request okay so now what I do
is I can actually use the loading status to my advantage to keep track of if the
API call is still happening or not okay so for example let me go ahead and console
log
loading and let me go into the other components and remove any other console
logs because we have a lot of stuff being displayed in the console and it's
starting to look a little bit confusing
so let me just make sure I don't have any other console logs okay so if you look
right over here we're
logging the loading status on line 17 in the app component so if you pay
attention you can see it says false true and then false and then false okay
so initially the status of loading is false when we make the actual API call
which happens when this use effect call back is being invoked we update the status
of loading
to true so that's why it trans it transitioned to true and then finally
when we're done with the API call we set loading to false okay so why this is
important is because we want to make
sure that once we have successfully finished the API call and we actually
don't have any errors and users actually defined with data we want to
set this user data State variable right over here okay and I know that this may
be a lot to takeen all at once but the reason why I'm showing you this is because
this is a realistic example of
how you would fetch data in a real application and then update the state and have
it apply in your in your
platform in your app okay so that's the reason why I'm showing you all of this so
here's what I'm going to do I want to
make sure that whenever the loading status is false so we're no longer
fetching Whenever there is no error and then whenever user is actually defined then
only I want to update user
data so first let me go ahead and set this to be an empty object and then we
might get a bunch of errors or yeah we might get some warnings I guess not but
our document is still working fine and then what I'm going to do is I'm going to
have a use effect hook right over
here so for the use effect hook inside the use effect hook I want
check to make sure that we're not loading there is no error and the user
is defined which means that the user actually has data itself it's not an
empty object or undefined because remember an empty object itself is also a falsy
value
okay so if all of this is true then I'm going to go ahead and call set user data
and then set it to user now we will need to have a dependency array because at
any point all of these values could possibly change okay and when it changes
we do want to make sure that we run this call back again otherwise we're not going
to get the accurate data for our
state so if loading changes we want to make sure that we tell react okay hey
the state of loading changed call this call back function again error may have been
updated at some point invoke this
call back again and then same thing with user okay and because we have this
condition as long as this condition is true then only we're going to update the
state of user data so now putting
everything all together if I refresh the page you can see now we have the ID of
two and then we have this email address that came from the API but you know let
me double check to make sure that I have the correct information I mean I think the
data that I had set over in some way
so for example we have ID we have uh instead of display name it should be
name you know what why don't I change it to name
instead uh let me change it to
name uh let's see I think this should be
[Music] okay we have a name and
then okay all right perfect so we have name email and username both
overlap uh let's see is there any other data I guess yeah we have all four
properties okay let me go into post container and I'll just render
everything over here so we have Name
ID email and then let's do username
okay now watch this if I refresh the page you can see that we have the name
the ID the email address email address and then I guess
their uh their name itself or what is this their username yep their username
and yeah this is all redundant stuff that was rendered from other components okay
and to show you even another
example that you could do if your data is still loading what you could do is
this and typically this is actually something that you would do using react react
suspense but we haven't got to
that part yet so I'll I'll just show you one thing that we could do if the load if
we're in the loading status you could
actually return a string that says loading and then if loading is no longer
true then you you can just return the post container so for example if I refresh
you see that if I if I refresh really
fast I don't know if you can see this but I you can actually see it over here there
is this loading text that is being
displayed over there but it is hard to notice um but uh that would actually
require us to have the API delay and be slow but um what I could do is I could
actually just go into use fetch user and I can actually
just do a set time out just kind of like simulate the API call giving us a delay
just just just as an example right and I'm showing you this because when you
build your application you'll have all of these things noted down so that way
you'll know how to you know display a
custom loading text or a spinner just to indicate the status of the API call I
refresh now you see it says loading and then notice how the moment when loading
goes from false to True 2 seconds
later it renders the post container component okay so hopefully this makes
sense so I hope this example although it was lengthy it was worth following
through because you learned a lot with you know how to create a custom hook to
fetch data how to properly set the state
how to properly check you know to make sure we're currently still fetching the data
and then making sure there's no
error and then making sure that our data actually is defined and then I hope in
general that you understand react context a lot better because it is a very helpful
tool that if used properly
it is very powerful and it makes your whole application a lot more easier to
manage okay so hopefully this all made
Intro to React Router
sense in this section of our react tutorial I'm going to go ahead and cover the
basics of react router now in case
if you may not know what react router is it's basically a library that allows you
to set up routing and navigation for
your appli application which is a very important thing in modern applications for
example if you want to have
different pages displaying different content such as a dashboard page a user
settings page uh maybe a logout page a guest page things like that you need
some kind of routing mechanism and react router does the trick it's been around
for a very long time I think probably since the early stages of react so it's
a wellestablished library I'm only going to cover some basic surface level stuff
with react
router there are a lot of topics and a lot of examples to go over and I think it
would be too much to fit into this
whole react tutorial so I'm only going to cover just the basics on how to get you
started I would recommend after
watching the section going to the react router website react router.com and just
clicking on their documentation looking at some examples and reading up on how to
do X Y and Z would definitely go a
long way so to get started we need to install the react router package so in
case if you haven't already known react doesn't come with anything except for the
two core apis which is the react
package itself and react Dom so we need to install react router it's a
third-party dependency so we're going to go into our terminal in my directory I'm
going to go ahead and type npmi and then the package is called react hyphen router
hyphen Dom just like this I'll
have it up on the screen for for you react hyphen router hyphen Dom you're going to
hit
enter and there we go we have it installed that was pretty quick and then we can
verify that it was installed in
our dependency section over here we are on version six as you can see right over
here now that we have react RAR Dom
createBrowserRouter
installed we want to import a couple of functions from the package itself now
keep in mind that so far in our application we only have just one page everything
that we were working with was
just our app component and everything was on the base URL but this time we're
going to have different pages mapped by its different routes okay so we want to
make sure that we actually go to our entry point of our application which is
going to be the main. jsx file where we have this reactdom doc create root
method being called and then we have our root app component being rendered okay
and what we want to do this time is first let's go ahead and import the necessary
packages or the necessary
functions that we need from the package so import from and then the packag is
react router Dom right over here and then we want to import create browser
router and then router provider now when you go on the react router documentation
there are a bunch of different ways that you can set up routing but this is the
recommended approach that the document a
suggest you to do so what we're going to do is we're going to remove this app
being rendered right over here and instead we're going to set up our router
provider it's going
to look like we're rendering the router provider but we're basically going to use
this router provider to set up all
of our routes okay so there's actually this prop called router that we need to pass
in and the value that we're going
to pass in will be an instance of create browser router so what we're going to do
is right up top over here we're going to declare a variable called router and then
we're going to call create browser
router just like this and you can see that the argument that it expects is an
array of Route objects so let's go ahead and just pass an array just like that
and what we're going to do is we're going to set up our routes inside this array so
if you want let's say five
routes you're going to end up needing to add an individual object for each route
assuming that they're all just root
routes so not nested routes okay I'll explain a little bit more in just a second so
for example we're going to go
Setting up Routes
ahead and set up an object and we're going to have the Path property sets
Okay this is going to be the actual location the actual path that we want to visit
in our
web application so we're going to set this to the base URL just a forward slash
okay and then what I'm going to do is I'm going to set the element property and
this is going to literally be either
the HTML element or your actual component that you want to render so for
my situation I want to have the app component being displayed
for I guess the base route just as an example so I'll do that real quick now
I'm going to go ahead and take the router instance I'm going to pass it right over
here so router equals and
then router and now let's go back to our web page and you can see that we have
pretty much the same thing doesn't really look like anything has changed and that's
fine we'll set up a couple of
more routes so what I'll do is this I'm going to go ahead and set another route
we'll
do path and let's do slash users okay for the
element I'll go ahead and just directly have a simple div because remember a div
is also a component I mean it's also valid jsx I mean really the component at the
end day is just going to boil down
to jsx with any state or props that are being used and other logic that needs to
occur so I'm just going to have this div set up over here and I'll just
simply go ahead and say users and now watch what happens when I go into my
address bar and if I go to to Local Host Port 5173 so my current URL but I go to
the users path you'll see now we get back this div if I open up the browser
tools if I go to elements you'll see that we have we still have everything inside
the root div nothing's changed
with that but when I go to the users path I get this div and then I get this
other div and then I get the user's text okay so you can start to imagine okay well
if I wanted to set up individual
Pages then what I could do is I could create a custom component let's call it
the users page and then have it mapped right over here and I'll show you how to do
that right now so typically what I
like to do is I like to create a separate folder in my source folder called
pages and I like to create a new file and I will go ahead and call this file
users page. jsx okay and then we're going to go ahead and create our component
because a page is still technically a component I mean it is a component okay it's
just we're just naming it a page
that's really it you can think of it like a root component that's going to hold all
the content in that page
itself okay and then I'll go and return a div and then I'll just go ahead and have
an H1 welcome to users
dashboard okay and then we'll go ahead and go back to our main. jsx file and
I'm going to go ahead remove this div and instead I'm going to render the users
page just like this and then we're
going to have that imported up top over here and now watch what happens when I go
back to the browser you'll see that
the users page component is being rendered to the document and we have our
H1 tag right over here with a text welcome to users dashboard okay hopefully this
makes sense and again you
can have as many pages as you want so I can create another page let's call this
blog posts page so this page could be
responsible for rendering blog posts made by other users I'll just call this
blog post page and then we'll just change this to
blog post page just like that and let's go ahead and copy this paste it right
over here let's change the path to blog posts and for the element we're going to
go ahead and just render the blog posts page though it doesn't want to Auto
Import that's fine I'll go ahead and just import it
myself there we go okay now let's go back to our address bar let's change the
path to /blog posts and now we are on the blog post page okay so I hope that
this makes sense it's pretty straightforward stuff you're you're basically just
setting up a path with a
different root component is really what's going on now another thing that you can
do with react router is having
Nested/Child Routes
nested routes these are also known as child routes as well child routes of the
root route okay so far these routes over here that we have set up are their own
individual root routes and each one of them actually has this children property
and you can use this to set up child routes or nested routes okay so for
example I'm going to go ahead and remove this users route right over here and I'm
going to actually set up the users's
route as a child route inside this uh base path right over here so this base
route will have child routes and it's going to look very similar to how we've
already been setting up our routes so
we're going to have an object okay because you can see that if I hover over this
the data type is route an array of
Route object object which is very it's pretty much the same thing as what you
pass in over here route object okay so I'm going to go ahead and set the path
to uh users and then the element will
be users page just like this so let's go ahead and try to go to slash users right
now so I'm going to go ahead and change the address to SL users and now you're
going to notice that right now the users page actually does not display at all
it's displaying let me zoom out a little bit it's displaying the contents of this
app component which is all of this stuff over here so one thing that you must
know is that when you have child routes this app component over here becomes the
parent route so it's actually going to render the parent element and then it's
supposed to render the child element as well well based on the path so in this case
it should render app the contents
of app as well as the contents of users but for some reason we're not seeing the
contents of the users page component now the reason why this is happening is
because we need what is called an outlet
Outlet
whenever we want to render child routes okay so the way that we can do this is
we need to go into our parent element which is the app element and then what I'm
going to do is this I'm going to go
into I guess I'll just do it outside the provider for now and then I'll go ahead
and just render this Outlet well let me import it first so we're going to import
outlet from react router
Dom uh let's see it should come from there yep import outlet from react
router Dom not sure why intellisense is being weird about it but let's just render
this as if it's a component well
I mean it is a component and now this will basically render the child element users
page so now watch what happens
when I go back to my application you can see when I go to slash users I can see
the root page element so this is the app component right here and I can see my
users dashboard component right over here or my users page component of course if I
were to go to just the base
page I'm only going to see what is on the app component I'm not to see what is
on the users page itself okay so you can actually use this approach to build
layouts you can you can have like a global navigation bar and you can have all of
your child uh paths like defined
over here so for example I'll just show you a quick example real quick I'm going to
go into my app component and I'll
just set up a very simple navbar I'll do it outside of the context
because we don't really need the context I'm going to use the nav component and
I'll use an unordered list and I'll just
have a very simple uh list item so we'll
have let's do this let's [Music] do let's do this let's do home and then
let's do users then let's do one for
blog and let me also make sure I change the url so this will be user and then this
will be blog
posts okay um this should be fine and
now let me move this into the children array right over here let me make sure
the paths are correct blog post okay so right now you can see I am in the
homepage the base URL if I click on users it takes me to users if I click on
blogs it takes me to the blog posts page if I click on home it's going to take me
back home okay now obviously since we are using uh these link tags it's looking
like we're refreshing the page if you wanted to avoid that from happening you
don't want to use a link tag what you would do instead is you can actually
just do this you can remove the a tag over here and there should actually be a link
component that comes from react router I'll show you how that works so let's go
Link Component
ahead and go up over here and let's import the link components
whoops here import link from react router domum and what I'm going to do instead of
using the the a tag for all
my links we're going to use the link tag or it's a component itself okay so what
I'm going to do is I'm going to go ahead and just have my home text right over
here and then we want to pass this to prop and this is going to be the actual URL
that we want to navigate to so the
URL that we want to navigate to is just going to be the base URL for home for users
it will be
[Music] users and then for
blogs it'll be blog posts okay and let's go back to our page
let's refresh and Watch What Happens so notice how now even though it technically
actually still is let me show you it still is an a tag
but it doesn't do that refresh behavior that it did before when we clicked on each
one you can see when I click on the
actual page notice how the data is not being refetch because before we were
actually fully re reloading the page
okay this time I can click on home be navigated to home I can click on users it'll
take me to users and you can see
the address bar is updating and then I can go to blog post page just like that
okay so hopefully this shows you an example of how you can have a root page
right over here you have your root element app and this is pretty much Global right
any child element that you
go to so if I go to users page will also have the contents of the app component
being displayed as you can see it's happening right over here okay so if I
actually just removed all of this stuff over here this provider stuff this would
look like a global navigation bar for my entire application okay so hopefully this
gives
you some ideas on how you can set that up now of course uh if let's say for
example if you want to have individual Pages without being rendered within the
actual root page itself then you don't want to have that path or
you don't want to have that route set up in the children array for the root path
you would want to have what we had
previously where we had this users path as its own root path itself
so now if I click on users you'll notice that it takes me to the users route and
it renders the users page but we no longer see that Roots app element on top
of it because we are in the users path right now and it doesn't have any root
element that it's rendering okay but if I go back and if I click on
blogs oops yep if I click on blogs you can see that the blog post page will
still render the app component because it is a child route of the base path
which is rendering the app component it can be a little bit tricky at first to
understand but once you play around with this which I encourage you to do like
try different scenarios out it'll begin to make a lot more
useNavigate Hook
sense now I want to show you how we can programmatically navigate users which
basically just means navigating a user based on either a condition or whenever
an event happens in other words we're not actually allowing the user to see like a
Navar and then clicking on links
like how we have it set up right now we want to make it so that let's say if they
click on a button and we listen to
the onclick event and then we navigate the user or if we fetch some data and if
the API call is successful then we'll navigate the user something like that is what
I mean when I say
programmatically right because right now I see this navigation bar I can just click
on these links that's not
programmatically okay I want to be able to navigate the user during the life cycle
of my
component or when some thing happens such as when we type to an input field
or if uh we receive a websocket uh data from the server things
like that okay so to do this we actually need to use a hook that comes from the
react router package called use navigate okay and this is a very popular hook
that you're going to want to know about so I'll show you how that works so I
guess a good example is let's do this
uh let's do this I'm going to go ahead and go into
my okay let's do this inside this use effect hook I'm going to go ahead and
navigate
the user to the user page once they have
successfully fetched the data and updated the state so in the app
component I'm going to go ahead and call this use navigate hook right over here
we need to import it of course so let's import that okay we're going to call this
and
it's going to go ahead and return a value so let's store that in this
variable and this value is actually a function specifically the navigate function
and you're going to use this
function to programmatically navigate your users to the route that you want them to
be at so for example
inside this use effect callback after we check for this condition if this is true
we're going to set the state and then I'm going to go ahead and call navigate and
I'm literally just going to pass in
the URL I want to navigate the user to so I'll navigate them to the users page
right over here the uses route and I can also pass options as well uh if I wanted
to pass like some State I could but I'm not going to I'll just call navigate and
since we are using this navigate function in inside this use effect callback it's
complaining that we need
to add this as a dependency so let's just do that as well it shouldn't really
affect this
logic over here so let's go ahead and see what happens so you can already see that
behind the scenes or in the
background it already did it for us already but let's go to the base URL and you
can see now see how it like
instantly navigates us to the user's dashboard now okay this is not really
the best examp example so what I'll do is I'll show you another example where we
can programmatically navigate users
Navigating Programmatically
so what I'll do is I'll set up an input field right down over here let's go ahead
and do this real
quick let's set up a div let's give our input field a
label uh enter data and then input and let's set the ID
to data I don't need any state for this because I don't really care about uh
tracking
the state of this input field I only care about the value of what we type in so all
I need to do is just listen to
the onchange event and then handle that events whenever it's triggered which is
basically whenever we type or paste the value or just whenever we change the value
of the input
field so I can easily just reference the event object target. value property so
let me just show you real quick make sure that this works of course so notice how I
can type and
whenever I type I can see the value of the input field being logged in the console
so what I'm going to do
is I'll just show you this as a very simple example if the
value is let's say the length of it is greater than 10 then I'll just navigate the
user to the blog post page okay
again this is just a very simple dummy example nothing complicated the whole
purpose is just show you how this
navigate function works that's really it okay so navigate blog posts and then
watch this I'm going to refresh the page so let's go ahead and type something that
is greater than 10 characters so
I'll type Anson the dev and notice how the moment I type that last character V
makes that whole entire string greater than 10 characters and you'll see that it
navigated us to the blog posts page
and that's how you can see over here that over here it says welcome to blog post
page because we are now in the blog
post page okay so I hope that this makes sense now very quickly I'll also show
Passing State to Route
you an example where we can pass State uh from the navigate function cuz that
was something that I did mention very briefly so for example if I pass in this
object I can set this state property and
I can literally just set any piece of value I want so for example I can literally
just pass in something like I
don't know posts and then id1 title posts or let's
do Hello World content welcome to my
first post okay so basically what I'm doing is when I navigate programmatically to
this blog posts page
I'm also going to send some state so it's basically is going to be an object that
has this post property which is an
array of post objects in this case now remember since this blog post path is
associated with our blog posts page because we set that up in our router
that means on the blog posts page what we can do is access the state that we
passed when we navigated to that path programmatically okay so this blog post
page we can access this post array I'll show you how to do that so in this
component what we want to do is we want to use this use location hook which comes
from react router as well so I'm
going to import use location from react router Dom and then keep in mind that this
use
location hook will return a location object it's not the same location object the
global one that is part of the
actual browser right over here so what I'm going to do is I will go ahead and
actually just name this router location
instead so that way we don't get confused and I'm going to call use location and
now watch what happens when
I console log router location I'm going to show you what this looks like it's an
object so let's go
into our page again and let me go back to the base
path okay so currently we're on the base path Let me refresh again so notice how
now if I go to the blog post p page this is the object that is the location
object from the use location return value right over here and you have basic
properties hash key path name search things like that but you see how we have this
state property and currently it's
null but notice how now if I go back to the homepage and let me type some stuff
into this input field so I'm going to type ANS in the dev so so I typed 11
characters so that navigated us programmatically to the blog posts page and you'll
see the blog post page is
being rendered and notice how if I expand this object now you can see that
the state property is now defined and the state property has this posts
property and as I mentioned earlier the state property is literally just an object
and it has this post property
which is what I set right over here when I did the programmatic Navigation okay so
what I
could do is I could reference the stat and I could get the post property you also
have to keep in mind that we need
to check to make sure that state is in fact defined as well as the post
property is defined as well because it's not guaranteed that the state will be
defined because you could actually
directly just go to the blog post page yourself and that would pretty much SC
skip this whole programmatic navigation right over here which means that there is
no State being passed okay so you
always want to make sure you check for that so what I could do is let me just
destructure this state property from
this uh use location call and then what I can do is this I can actually probably
do something like this I can probably wrap this in the use effect
hook and then what I could do is I can use the
state object as my dependency and I can check to see if state is defin and if
state DOT let's do posts is defined then what I could do is I can
actually Define some local state for my blog post page so let's do
that so this will be an array of posts so if state is defined and if the
post property is defined which is an array then we'll go ahead and call set posts
and we'll just pass
in state. posts just like that okay and then down over here I will render
posts so we'll do post. map and then we'll go ahead and just render a simple
div for each post and we'll render the title and the content so what I'll do is
I'll do an H2 tag render post. tile and then I'll have a section where I'll
render a paragraph post. content is very simple markup let me go
and make sure I use the post ID as the key for my div can't forget that and
let's go ahead and see if this works so let's go back into our page now notice
how now if I refresh you'll see that we actually still have the
posts um right over here which implies that this state and state. poost
property is defined and even though when I refresh the page we're not doing the
programmatic navigation anymore now you
may have also noticed that even though when I refresh the page I actually still
have the state right over here I have my
posts right over here even though I didn't do the programmatic navigation right
because the way that we set up our
code is that when we type more than 11 charact or more than 10 characters it's
going to programmatically navigate us to
the blog post page as well as send some state to that page that we can access
but I'm refreshing the page and you can see that I still have the state so the
state is still present and I still have
the posts now the reason why this happens is because actually behind the scenes
what's going on is that the state
is actually stored in the browser's history okay there's a history API that
is being used and I could probably show you right over here if I were to console
log window history and then let's see there should be the state property it
should be stored right over here so let's see we're on line8 so let me zoom in a
little bit so you can see right
over here yep right over here you can see that the state is still over here
when I refresh the page no matter how many times I refresh that state is still
stored in This Global window object
which has this history object right over here and then we have this state object
okay now if I were to actually go to the
homepage so I load up the homepage and then let's say if I go directly to the blog
post page you'll notice that now we
no longer have that State anymore so kind of like cleared and you can see
that over here there's no state in the global window. history object and then
State over here is null which is from the use location hook okay so I just
wanted to bring that up and in case of you are wondering like why it was the case
that we still had our post even
though I refreshed the page okay that's because that state was stored in memory
so that it can be accessed easily okay so but if I were to go back
here let's go back to home go to blog post stay is still undefined that's fine
let's go back to home let's type anev now we have our state we're on the blog post
page I can refresh as many
times as it want it's still going to have the state and another thing that I will
mention is that you'll notice that
if I go to the blog post page right now let me just type some stuff so we have our
state but you'll notice that if I go
to the base path like this where I manage it in the address bar and I hit
enter the page itself actually refreshes like the entire window refreshes right
and then if I go to the blogs the blog post page I no longer have my state and
that's because like if I were to navigate in the actual app and not through the
address bar so let's say for
example if I just type and now if I navigate in the app I still have my state
because that state is still saved
in the window but when I go to the address bar and if I change the address
itself I change the path and if I hit enter this reloads the whole entire page
so that state is going to be cleared so that's the reason why if I go to blogs
right now I no longer have that State
and if I were to go to blog post directly here I no longer have that state so I
just wanted to mention that
in case some of you might be having questions about
Intro to Unit Testing with Vitest
that in this section of our react tutorial I'm going to teach you how to test your
components now I'm not going
to give you a whole explanation on why you should test your components in react it
should be pretty obvious but if it
isn't I will quickly mention why you should test every single developer should
learn how to test their code because when you are
deploying your product to your customers you want to make sure that your
application has the least amount of bugs
possible notice how I said least amount of bugs and not bug free because there
isn't any such application that is 100%
bug free there is always going to be some type of bug that is introduced in your
application whether it was because
you improperly handled some kind of uh use effect or some kind of algorithm or
maybe a new feature that you wrote introduced a bug into the application testing
allows you to ensure that each
time you write some code or if you introduce a new feature that the current
state of the application does not break the behaviors of the application remain
the same okay so there's a lot of things to talk about when it comes to the
fundamentals of testing we're not going
to dive into that I'm just going to teach you how to write unit tests for your
application and then we'll dabble a little bit in some integration tests using
something called a mock service
worker so with that being said the tools that we're going to be using are vest
which is a testing framework and we're
going to be using react testing Library so normally before vit was popular when
everyone was using Create react app we would use just and then we would use it with
something like enzyme or react
testing Library enzyme isn't really as popular anymore I don't really know if there
are people still using it but
react testing library is the go-to library to use to test the behavior of
your react application so that's what we're going to be using so we need to install
a couple dependencies and set up
our project in order for our test to correctly run and it's nothing complicated so
what we're going to do is
we're going to go into our terminal so inside my react tutorial directory I'm going
to install a couple of packages so
Setting up Vitest & React Testing Library
I'm going to type npmi hyphen D these are all going to be Dev dependencies because
all of these
relate to testing and testing is primarily for the developer experience not really
for your customers to see
okay so we're going to install vest and then we're going to install at testing
hyphen Library forward SL react and then we're going to install
jsd and then we'll hit enter now that we're done installing our dependencies we're
going to go into our
code repository or our project and the first thing that I'm going to do is go into
Configuring vite.config.js for testing
the V.C config.js file and we're going to set up this file for tests so inside
this object that has passed into the defined config function that is called we're
going to go ahead and set up this
test property which is an object and this allows you to to configure your
tests so the first thing that we're going to do is set up the environment and we're
going to set that to jsd and
we need to make sure we have jsdom installed which we just did okay if you
don't have jsdom installed and when you try to run your tests using Vest it's going
to throw an error and tell you
that jsd is not installed the next thing that we're going to do is set up this
property
called setup files and you may recall this was something something that was done
with create react app but we're not
using Create react app obviously so we're going to have to set this up ourselves so
we're going to basically
have this setup files property ma to a file called setup
test.js which we don't have currently but we are going to create so I'm going to
have this setup test.js file okay
that's going to be in the same directory as my config file for vit so we're pretty
much done with this this so what
I'll do next is I'll go ahead and create that setup tests file so in the same
directory or you can create this wherever you want I'm just going to create in the
same directory as my V.C
config.js file I'm going to create the setup tests. JS file and now in this
Create setupTests.js file
setup test.js file we're going to actually need to import a couple of
functions so first I'm going to import after each and this is going to come
from the V test package then we're going to import this cleanup function which is
going to come
from the testing library for react package now there actually is another
package that I did not install and we're going to install it very quickly and that
is going to be the at testing hyen
Library slj we need this package as
well okay there we go and now what we're going to do is import at testing
Library slj Dum and we want to import v test over here okay and then what we're
going to do is we're going to call the after each function so this is a hook if
you've used just before this is pretty much very similar pretty much after each
test it's going to invoke this callback
function and all we're going to do is just call the cleanup function like this
okay and then we're pretty much done with this setup tests file and what we want to
do next is we
want to go to our package.json file and set up a test script so right over here
I'm going to set up the test script and then it's going to execute the vest
binary okay and you can see right over here in the dobin folder in our node modules
folder we should have that
vest uh package right over here
okay pretty straightforward stuff hopefully that makes sense so whenever we run our
npm script it's going to go
ahead and execute this vest binary for us so that's going to run our tests so
this is pretty much a very very easy basic setup if you need more different
things to configure you can go to the vest documentation and just click on config
and then there are a bunch of
things that you can configure here for your application okay but this is going to
be
just the bare minimum that we need so now what we're going to do is create our very
first test so what I'm going to do
is I'm going to go into my source folder and I'll create a new folder and typically
what developers do and this is
industry standard is they create a folder called uncore uncore testscore
underscore and the reason why for the underscore is because it actually moves the
folder all the way to the top of the
the folder tree so you can easily see where it is instead of having to dig through
a bunch of different directories
you don't have to put it inside the source folder if you prefer you can put it
outside the source folder but I'm just going to keep it inside the source
folder for now now I don't want to make this first example very difficult for
Writing our First Test
all of you because some of our components are using things such as the context API
some of them are using react
router and then we're using uh we have a component that is fetching data from an
API
and I don't want to just immediately scare all of you when it comes to testing so
what I'll do is I'll just create a very easy component I'll just
call this username display. jsx and then all this component is just
going to do is just take in a prop a username and it's just going
to render it and that's all it's going to do okay that's literally all this
component is
going to do very simple and I'm going to show you how to test this it's complaining
about the prop valid I'm not going to worry about that right now
because it's not going to affect our test at all so what I'm going to do is since
my component is called username
display I'm going to want to create a test file that is matching the component name
because that allows me to keep
track of it so I'll call this username display and then we want to use the dopc
extension or test extension you can use either one and then you want to end it with
jsx so if you do uh test. jsx this
would work fine if you wanted to use. spc. jsx that would also work fine as well
okay so now what we're going to do
inside this file is first we're going to import the describe function from vest
there is a way to actually set up these functions globally uh I tried looking it
up on Google but I think it primarily works with typescripts I wasn't able to
get it working so for now we're just going to import these functions manually from
the vest package okay so I'm going
to import describe and then I'm going to import it these functions may be very
familiar if you've used just before or something similar so describe is a
function that's going to allow us to set up a test Suite so in other words it
actually allows us to group together our tests we don't actually write the testing
logic inside our described
function body we just use it to label our test and group them together okay so
what I'm going to do is I'll just go ahead and give the describe a name inside
these inside these parentheses as
the argument over here so I'm going to go ah a and just call this username display
just very very basic stuff for
now okay and then we're going to to pass in a callback function as the second
argument this is
how every single describe is going to work you have the name of the test suite and
then the Callback function and then
inside the Callback functions body is where you actually are going to set up your
tests using the it function or
alternatively you could actually also use the test function as well so if you
wanted to write your first test you
would use the it function or the test function and it would look something like
this so let's say for example uh
for my name I'm going to go and say it should render username okay and then
pass in the Callback function and then this is where you would write your testing
logic if you wanted to use the
test function instead it'd be the same exact thing okay the same exact thing
same arguments it doesn't really matter which one you use at the end of the day
okay so as you can see right now what I'm doing is I have my describe my test
suite and I'm just giving it the name username display inside the body of the
test sues callback function is where I'm going to use the it function to actually
write my tests okay so what we want to do is for the first argument you always
want to describe or you want to label what the test is actually going to do so in
this case I'm saying okay it should
render username and that's what our test should do it should that's what it
should test for okay so we're going to write our testing logic inside uh this
callback function's body the one that's passed through the it function and this is
how we're going to do this
okay with every single test in react when it comes to testing components we want to
make sure that we first render
the component that we want to test so in this case we're trying to test the
username display component so we want to
Rendering Component Under Test
render that component now here's the question how do I render that component you
might be wondering well do I import
the component so let's import our component first and then do I just do something
like username display like that well not quite so this is where react
testing Library comes in so we're going to use react testing library's apis to
actually render the element to the document and then we can actually use a function
that comes from vest called
expect to write assertions okay so what I'm going to do is I'm going to first
import whoops I'm going to import this render function from the
testing Library react package this is something that we installed earlier in
this section of our tutorial and what this function allows you to do is just render
your component or element
whatever it is that you want to render into a container and then that's pretty much
rendered to the document itself the
body of the document okay so what I'm going to do is I'm going to call render
and then we want to pass in our react node so it's basically going to be our
component over here username the display but we're going to pass it as if we are
rendering it like this okay so you want
to make sure you pass it like this as if you were actually writing jsx instead of
passing in like this okay so that's pretty much it with rendering our
component and now what I'm going to do is I'm just going to show you how you would
actually execute your tests so
right now we have no assertions so our test actually should pass so what I'm going
to do is in my terminal I'm going
to go ahead and execute that test script that I implemented in the package.json
file right over here so we're going to go ahead and type npm run test and that
will execute the v test script and you're going to see that's going to run our
username display. test. jsx
file okay and let's see what happens okay there we go so you can see
that nothing errored out with which is fine and nothing uh nothing bad happened
of course it's going to pass we haven't written any uh we haven't wrote any
assertions one thing I do want to mention is this render function actually returns
an object which is an instance
of render result so we can assign it to a variable and there are a bunch of
different properties that we can reference you don't really need all of these but
sometimes some of them may be
useful so I'll show you an example where we do something called snapshot testing
with the container because right now
this container itself actually gives you the HTML element so for example if you
hover over this the type is HTML element
and there are a bunch of properties that pretty much you would see on any HTML
element itself so what
Snapshot Testing
I'm going to do is I'm going to show you one type of testing called snapshot
testing which is very common and it is
not as popular and it really isn't super important but it can be very useful in
many situations okay so what I'm going to do is I'm first going to need to import
the expect function and this is
going to allow me to write an assertion so what I'm going to do is I'm going to
call the expect function and I'm going
to pass result. container because I'm going to write a snapshot test on the
container itself on the HTML element and
then there's going to be this matcher called to match
snapshot and I'm going to go ahead and just call that function right over here it's
just a function on the return value
of expect okay now I'm going to go and save this and let's go ahead and run the
test again and I'm going to show you
what happens when we create a snapshot so you're going to see in the in the
console in just a second it's going to go ahead and say snapshots one written
okay and you can see that on the left hand side we have this snapshots folder that
was created and then inside that
folder it created the this file same name as our test just ending with a snap
extension let's click on this and you
can see that right over here we see our test Suite username display and then we
see the actual test name that was ran and you'll see that right over here we have
the HTML that is displayed right
over here and that is coming from the container itself so why is this important
well snapshot testing is a way
for you to whenever changes happen to your UI whether you made it yourself
either purposely or accidentally and this is useful because sometimes you might
have a UI that you don't really
expect to change at all perhaps that UI is only supposed to display static
content and you don't expect it to change at all okay and then let's say
you have a snapshot test and then your snapshot test fails because now the UI is
different
so what happens is it fails and it tells you about that and then you can go back
and review the test and say okay is this
snapshot test failing correctly or do I just need to update my Snapshot so for
example right now what this is basically
doing it's it's kind of like taking a photo of your UI okay and it allows you to
keep track of what it looks like if I
were to go to my UI right now and let's just say for example I change this from a
span to an H1
okay and then if I run the test again which automatically does this you'll see
that now the test actually fails and you can see that it says expected a span but
we received an H1 tag so what this snapshot is telling me is saying okay
well your your snapshot test failed because the original snapshot that we took we
had a span but now your UI says
it's an H1 tag so you have two choices go back to your UI go back to your component
and revert the changes from an
H1 tag back to a span tag or update your snapshot okay there's no right or wrong
answer here it's just really up to what your intentions are if your intention was
to actually update the component and
actually replace it from a span to an H1 then all you need to do is update your
snapshot and you're basically saying hey
the previous snapshot is old we no longer care about it anymore it's obsolete
update the snapshot so right
over here it tells you press U to update snapshot so if you press U you're going
to go ahead and see now the snapshot was updated instead of it being created and
if you go back to the snapshot file you'll see that now it's an H1 element instead
of a span hopefully this makes
sense now obviously this whole tutorial is not about snapshot testing I just want
to very quickly show you how that
works let's go ahead and actually write the test that we wanted to which is
ensuring
that the username is being rendered to the document so what I'm going to do is I'm
going to go and just comment this
out and I'm going to change this back to a span we no longer care about our
snapshot test so I'll just comment that out for now and what I'm going to do is I'm
going to go ahead and write an
assertion to verify that the username is being displayed to the document now
you're probably wondering well okay I need to make sure that the username is
actually first of all being rendered how
do we make sure we do that well here's the thing though right now we are passing
the username display node to the
actual render function to have it render but if you didn't notice in the snapshot
test you'll
notice that right over here we actually don't have any text being rendered at
all it's just an empty H1 tag or it's going to be a span tag now and the reason why
is because we're not passing
any props to our username display component remember that your components if they
have props you need to make sure
you're passing them otherwise if it's being rendered which it is it's just going to
be empty which is why you saw
that right over here nothing was being displayed at all okay well the H1 tag
was there but it was just empty so let's go ahead and pass our prop so we'll do
username and then we can just literally
pass anything we want I'll just pass ants in the dev and then now what I'm going to
do is just very quickly I'll
actually run this test again just to show you uh what this
looks like and then you'll see that in the snapshot you can see we actually have
our span element with the actual
user R because we passed the prop into the component okay so anytime you need to
test a component that expects props
or needs to receive props you just pass it in regularly as you would in just plain
jsx okay so what I'm going to do
is this I need to verify that the username is on the screen it's in the
document now the way that we're going to test our user interface is by using this
Using Screen to Query Elements
screen API which comes from react testing Library so we can import
screen and this screen is a constant and it has a bunch of different methods that
you can use to query your document to look up elements find elements search
for elements things like that okay and there are a bunch of different ways that you
can search for elements you can
search for them based on the text you can search for the elements based on their
test ID which I'll explain a
little bit more later on you can search for elements based on their role such as if
it's a button if it's a text text box
if it's a list I'll explain a little bit more about that as well you can look up
elements based on a bunch of different things label text uh display value
that's for input Fields um things like that okay so I'll show you an example
where we can search for our username based on the text using the
screen API so what I'm going to do on this screen object is I'm going to call
getByText query
the get by text function or query I'm going to use those terms
interchangeably okay and this get by text query takes in a couple of
arguments so for example the first argument is going to be the matcher itself so
here you can either pass in
the actual string value that you want to search for or you can pass in a regular
expression to match the string in the document so for example I know that my
component is supposed to render the
username an the dev so I can pass in ANS the dev like this if my text is more
complicated perhaps maybe I might be concatenating my text with a bunch of other uh
texts as well I could use a
regular expression like this okay whatever you need to do either you need
to pass a string literal or a regular expression I'm just showing you these two
Alternatives okay since our text is
pretty simp simple I'm just going to use a string literal so what this will do is
it will make an attempt to find the element in
the document if it cannot find the element based on this text an the dev
what will happen is it will throw an error so get by text will actually throw an
error or if it finds two elements
that are associated with text with this text so if it finds let's say two span
elements with the same text an in the dev it's going to throw an error and you'll
see in just a second how that
works so right now we only have one HTML element the span tag the span element
with the username an in the dev so this test should be fine so what I'm going to
do is I'm just going to copy this copy this and then I'm going to call expect
and then just pass this screen. get by text call into expect okay and then what
we want to do is just call the matcher to be in the
document okay so basically this assertion that we're writing is we're asserting
that
this this uh an in the dev text is in the document okay there is an element
with the text ant in the dev that is in our document okay that is what this
matcher will do for us it will verify that it is in the document okay so since
I don't need this result object anymore I'm going to go and just remove this part
we still need to call render now
let's go ahead and run our test again and let's see what happens uh you can see
that it actually
did pass but I'll just rerun it again just to show you uh let me actually update
the uh let me do this okay so we removed the snapshot cuz
we no longer need it so you can see right now my test actually passes okay okay so
let me go ahead and do one more
thing let's go ahead and actually just pass in a value that I know is not in the
document just to make sure that we
don't have any false positives which could happen occasionally so I'm going
to pass an ants in the devs with an S and I look at the console and you can
see our test actually fails so this verifies that my test that passed
previously is actually passing correctly okay so you can see over here we get
some feedback it says unable to find an element with the text an the devs with an S
and it gives you some uh hints on
why that could possibly be the case and then it renders the body right over here
and then or the HTM element which is a body and then you can see we have our divs
and then we have ANS in the dev
right over here okay and then it goes ahead and points out what's the possible
issue you get the point okay and I'll show you an example where where I can
use a regular expression so let's just say for example I only care about matching
the text Anson with a regular
expression and then you can see my test actually passes if I were to do let's
say if I just did something uh I don't know let's just say um
H I guess developer let's try that that will fail okay but if I did
Dev this would pass because Dev is part of is a substring of ants in the dev so
that matches so it's going to pass okay now let me put this back to a string
literal and I'm going to show you what happens when I actually render the username
two times and I'm going to show
you how that affects my test itself so now you can see that
when I look at the console after my test reran it's going to go ahead and fail
and it says found multiple elements with the text an the dev and that's just the
nature of this query get by text and if you look at the documentation it'll tell
you right over here uh the get by family of queries so get by text get by label
text get by display value get by rooll etc etc all of those queries will fail
if it finds uh more than one matching element for the query okay so it tells
tells you to use get all bu so if we wanted to search for or if we wanted to
write a test to assert on multiple elements we would want to use get all by
text instead okay so get all by text and S the dev to be in the document and then
now let's see what happens uh received value must be an HTM element or an SVG
element well you know
this time this actually returns an array of elements so we would have to actually
modify our test just a little bit so uh
what I could do is this since this is no longer an actual HTML element itself it's
an array
of HTML elements so I probably would have to uh iterate through let me see if
there is let's
see uh let me do this
I'm do cons elements equals get all by text so now I have an array of HTM elements
and then what I could do is I
could just do elements for each elements expect
elements element to be in the document there probably is a simple matcher that I
can
use to uh check all elements on the documents but off top of the head I'm
not really sure about that maybe some of you that are experienced with react
testing Library can tell me uh but yeah
you can see right over here I'm using a for each method on the array of HTML
elements and I'm writing assertion for
each element verifying that it is in the document and our test passes if I were
to negate this using the not assertion right over here or the or the not
operator you're going to see that it actually fails because the element is actually
in the document okay so
hopefully this makes sense now before we move on I wanted to spend
Understanding getBy vs queryBy queries
some time to explain the difference between the get by query versus query by so for
example
some of you might be wondering well okay instead of using get by text why don't I
just use Query by text instead and if I
were to rerun the test you'll see that it passes and it works just fine so why
do I use get by text when I use Query by text or the other way around so this
leads to the question when should I use get by text versus query by text like
what's the catch using one over the other so the important thing that you must
understand is this so I'm going to
show you this documentation right over here because it's a great point of reference
so the get by query and the
query by query they both return the matching element from the query itself
so when you call query by text or get by text
it's going to go ahead and return the actual element itself granted that it's found
in the document itself but here's
the part where you need to understand the way that these functions handle when
the element is not found in the document is different so if you look at this part
over here where it's describing the get by category you'll see that right over here
if the element is not found in the document then it will throw an error for query
by
if the element is not found in the document it will not throw an error but it'll
return null okay now you're
wondering well what's the purpose of this Well here here's the purpose of this so
let's say for example if you're
trying to test for an element that does not exist and the documentation tells
you right over here to use Query by to assert elements that are not present in
other other words the elements don't appear in the document itself then you want to
use Query by because it's not
going to error out if the element was not found so you can easily write an
assertion that says okay well this element is not found so I expect this element to
be null okay whereas if you
were to try to test for absence of an element using get by well it's going to
be difficult because it's going to error out and I'll show you an example so what
I'll do is I'm going to go ahead and
remove uh this username right over here I'm going to remove the render of the
username and I'm going to show you right over here so you you'll see that the the
test actually fails right now but it's
not failing because of this 2B in the document matcher it's failing because
this get by text is uh is erroring out okay you'll see that it says unable to
find an element with the text and it points to this part over here it's not failing
because of this I could
literally do something else like I could do something like to be I don't know to
be checked like just let's just use some random matcher okay and when
the when the test runs again you'll see that it's pointing to this part over
here not this part okay so it's not the matcher it's the get by text and go
further to go a step further I will just call get by text and you'll see that now
our our our function still errors out okay unable to find an element with the
text an in the dev because it doesn't exist okay now watch what happens when I use
Query by text
instead you'll notice that even though the element is not in
the document it clearly isn't it doesn't error out and our test falsely passes
okay so now you can see the difference between query by versus get by and this
is the same for all variants of the query by or get by text so for example
it's the same thing that happens if you were to use get by roll or query by roll
okay so now that you understand the
difference between both let's show you an example how you can handle the situation
when they're not in the
document okay so let's say if you're adamant on using get by text for whatever
reason because you enjoy using
get by text but want to test for an element that doesn't exist in the document well
how would you do that well
the way that you would do this is not by actually writing an assertion that the
element doesn't exist in the document
you would actually write an assertion on the error object itself so the way that
that would look like is like this you
would use a tri catch like this and then what you would do is this you would you
would uh call
screen get by text and then and the dev and then you basically write the
assertion on the error object to be defined now obviously this this error
object is always going to be fined because first of all you are setting up your
test in a way for this get by text
call to fail and in order for this error object to be defined you have to be
inside this catch Clause anyways right so this is one way to do it the other
way that you can do this is uh I'll show you let error equals we'll just do let
error we'll Define a uh we'll declare a variable called error and then I'll do
error equals error like this and again this is a very hacky way to do things I
would not recommend doing it but there
are times where you do need to write a test using TR catch not for this case
because we have a query by tool to use so we're not going to obviously do it this
way I'm just
showing you an example okay so this is what you would do right you would pretty
much just kind of like hack your way through this we know that this get by text
call will fail so inside the catch
block we're going to go ahead and set error to error and then right outside the
catch block so we're going to write
an assertion on the error object to be defined now obviously if get by text uh
doesn't fail then this will be undefined so this whole test will fail okay now
again I would not recommend doing it
this way I'm just showing you it because if you're very adamant on doing it this
way and if you have to use get by text
and this is what you would do at least this is what I would do if I needed to do it
but I wouldn't do it this way okay
instead the correct way that we want to do this is like this so first uh here's
what I'll do we're going to go ahead and
call query by text and then we'll go ahead and pass in the text that we want
to query for that we know is not in the document okay so then what I'm going to do
is I'm going to copy this and I'm
going to pass it into expect and now we know that the query by query will return
null if it's not found in the document instead of erroring out so what I can do
is I can say Okay expect this whole thing to be undefined like this well
actually not to be undefined uh two well we wouldn't use to be undefined because
null is technically not undefined like
that null is actually still a value is not on theine we want it to be
to B null I guess yeah 2B null is the correct one sorry about that and now you'll
see that the test actually passes
now there are other assertions you could use like for example there's not to be
in the document and you'll see that our test passes so we're writing an assertion
we're saying okay this text an the dev is not in the document because it
findBy queries
clearly isn't and then we can see our test passes okay now of course if I were
to change this to be Tob in the document our test actually fails and you can see
that the receed value must be an HTM element or an SVG element and that's
complaining because this value over here
is null okay so again I hope this makes sense and I hope that you better
understand the difference between using get bu versus query by now there is a third
type of query
called find by so for example I could have also used find by text instead of
query by text but you're wondering well when should I use the find by queries
instead of using get by or query by in order to understand this better let's first
understand what exactly F bu
returns and the behavior of it so right over here it tells you that find by so
in our example find by text returns a promise so that should tell you right off the
bat that it is
asynchronous okay get by and query by our synchronous okay so it returns a
promise which resolves when an element is found keyword when an element is
found so that's basically implying that sure maybe the element might not appear
right away but eventually it
will okay now here's the other thing that you also need to understand is that the
promise will reject so typically
that means that the promise is erroring out it's rejecting if there's no element
found within a default timeout of 1,000 milliseconds or 1 second or if more than
one element is found so similar to our get by uh
query okay so basically the the reason why you would want to use the fine by
query is whenever you're dealing with elements that take time to render to the
document so in our example our elements appear instantly to the document they're
all pretty fast right like our username just instantly renders so there's no
logic that is occurring the username from taking you know 5 seconds from appearing
to the document but you might
write some tests that will often need to fetch an API or it will perform some
kind of complicated logic that will cause the element to appear in the document
after like 2 seconds like give
or take 2 seconds or 3 seconds as an example I'm just throwing in a random number
right so in a situation like that
you want to use fine by queries because it allows you to wait a certain
amount of time to search for the element to appear into the document
okay so for example I could use find by text instead of query by text or get by
findByText example
text so let's say for example I'm going to remove this whole thing and I'm going
to go ahead and call screen. find by text and then pass in my text and in the
dev that I want to search for and then remember that find by text is a
synchronous it returns a promise and you can see over here Returns the promise now
what I want to do is I'm going to go
ahead and copy this and passes into expect and paste this right over here
but keep in mind that this is a promise so by just passing this right over here
or I'm sorry this returns a promise so by just passing this call over here I'm
trying to write an assertion on a
promise not the actual value the return the resolve value itself in other words
the actual HTML element that we expected to return so I need to actually await
this call so I can add the await keyword in front but we need to make sure that
we're inside an asynchronous function so
I'm just going to go ahead and add the asyn keyword in front of my function for the
test itself which you can do and
then now what I can do is I can call 2B in the document just like this and I'm
going to save this and when I look at my test let me go ahead and just run this
again you're going to go ahead and see
that it passes and now this works perfectly fine let me try to make it
fail and now you can see notice how this time the test actually uh took some time
to actually execute I don't know if you may have noticed but there was like a
little spinner I can let me try
rerunning it again you see how right over here there was that little uh spinner
that was occurring so it it was
waiting up to uh I guess 1,000 milliseconds I guess it kind of went a little bit
over but that's okay it was
basically waiting 1 second to find that element and it wasn't able to find it as
you can see over here in the documentation it clearly tells you that the default
timeout is 1,000 m seconds
and then uh it rejects okay so that's the reason why right now our test it tells
you that it was not able to find
the text an and devs now what I can also do additionally is I can pass in a second
argument and I can go ahead and set the timeout uh let's see I guess not here
but let me do let me just pass in an empty object and then let's do
timeout and I'll do 5,000 milliseconds so we'll give it some more
time just to show you that that's why this is spinning and now you'll notice
that when I restarted the test it took 5,000 milliseconds and then it
rejected okay there you go you can see right over here that it's giving it
enough time 5 seconds for the text to appear in a document okay I can set this to
any number I want I can set this to
10,000 if I want to but I'm not sure vest will allow that I think vest has a
default value for tests yeah you can see
right over here that uh it seems like vest does have it set to it does have it
capped at 5,000 milliseconds so you could change if you want to uh I believe right
over here in the test you could
set the time out to whatever you want so I'll set this to 20 ,000 milliseconds by
default it was five so now you can see that let's run the test again
though I may need to fully restart my test because I made changes to the
configuration so let's run it
again and now you can see that it is running longer than 5
seconds and it's going to be it's going to time out at 10 seconds okay and you
can see that it took 10 seconds to search for the element by its text an
inadev and it was not able to find it so it just errored out it just it just
rejected okay so hopefully this proves
to you that this is indeed why we would want to use find by text whenever you're
dealing with elements that may not
instantly appear in a document okay so let's just pretend like this is some kind of
API call and then finally we get
the text is appearing into the document right so what I'm going to do is I'm going
to change this back to anad
Dev and uh what I'm going to do is I'm I'm going to go ahead and uh
render this username to the document but only after uh 5 Seconds have passed now
the way I'm going to delay the render of this username is like this I'm going to go
ahead and Define some State I'll just
call this uh I guess uh timer P set
timer past VI State and then I'll just call
I'll just set this to to be false I'll go ahead and use uh a use effect hook CU I'm
going to
perform a side effect I only want the side effect to run one time I'm going to go
ahead and call set timeout so
basically this is how I can delay uh the execution of this call back
so I'm going to set this to 5,000 milliseconds so after 5 Seconds have
passed it's going to go ahead and execute this call back right over here and all
I'm going to do is just call set
timer pass true and I'm going to set the timer P state to True right over here
okay and then I'm going to go ahead and conditionally render username so timer p
and username just like this okay so now Watch What Happens let's see let's go
over here so now our text our username is going to render but only after 5
seconds so let's go ahead and you can see that our our test already passes but
let's just rerun it again and now you're going to see it's going to take up to 5
seconds and after 5 Seconds it was able to find that username because that
username it took 5 seconds for it to render because when the component renders the
current state of timer p is
false so the username is not being rendered okay and also remember that when the
component first renders it's
going to go ahead and invoke this callback for the use effect hook so it calls set
timeout uh it calls the
Callback function of set timeout after 5 Seconds have passed and what happens set
timer pass is called it updates the state to true and then when the State
updates it's going to go ahead and render and then render username okay so
hopefully this makes
sense I could change this to literally any value I want so 1500 seconds I'm
sorry 1500 milliseconds and then you'll see that the component uh let's restart the
test again you'll
see that the test will pass and it'll and it will
basically uh pass after the amount of time it took for the element to be found
so since I rendered the element after 1500 seconds you can see that it no
longer is in this pending state for it to pass after 1500 milliseconds because it
was able to find that element so it
is I believe it is you know trying to actively find it periodically within that
time span so hopefully this shows
you how this works and again you can pretend like this is some kind of API call
that is happening and then once the
API call is done it's going to go ahead and render that data to the document and
there we go we found it okay and for example I can change this timeout to
1,000 milliseconds or I can just remove this and have it be capped the default
which is 1,000 milliseconds and you'll see our test is going to fail because it
took our it it took 1500
milliseconds for this username to be rendered but the default timeout for
find by text is 1,000 milliseconds okay so after 1,000 milliseconds it's just going
to error out okay so this is just
a tip so in case if you have something that may take longer than 1,000
milliseconds definitely make sure you pass in that third argument and set the
timeout field do however long you think you may need okay so hopefully this makes
sense now I did spend some time teaching you about how to actually test your
More examples of Testing
components with basic stuff right and I also wanted to make sure you understood
how to use the different types of queries such as get by versus query by
versus find by not understanding when to use which one is is a very common
mistake that many developers run into and it leads to writing poor tests with
inaccurate results so it's important to understand the difference between all three
of them so I'm going to move on
and show you more examples of tests so I'm going to show you how I can test a more
complicated component that has a
bunch of more different elements so for example I'm going to show you how I'm going
to test this user details
component in order to do that first I'm going to render this component to the
document so that way you actually can
visually see what this component looks like now the way that we render this
component we actually do need some State because if you haven't been following
along with the entire tutorial you may have missed on how this user details
component was actually supposed to be used so it was actually a component that is
supposed to be rendered uh based on a
a list of users so what I'm going to do very quickly is I'm going to Define some
state
and I'm going to call the dispatch function set users because our user details
component actually took in this
set users function which is a dispatch function or an updator function to update
the state of the users array
itself okay so what I'm going to do is I'm going to go ahead and set a fake user
we'll do ID of one username an the
dev and then email anen gmail.com okay and these are all of the fields that we
need need for our user object because remember the user details component it
takes in two props a user object and the dispatch function and that user object
needs to have an ID username and email property okay so let's go ahead and
write down over here and notice how I comment out a lot of stuff in my app
component because I don't want to overwhelm you all so here's what I'm going to do
uh let's see I'm going to go
ahead head and do this uh I'm going to go ahead
and render the users so users do map and
then we're going to go ahead and pass in our call back and then we're going to
transform
each user object into a jsx element so let's set the key to user. ID and then
we'll pass in the user object like this and then we'll pass in set users and that's
just going to be this dispatch
function over here that was returned from the UST State call hook or the UST
State hook call okay and then if I show you this you'll see that this is what
our uh user details component looks like and again if I have multiple users there
will be two users appearing okay we're only going to stick with one for now so
when I click edit I can edit the username I can go ahead and edit the email address
whatever I want
right very very simple stuff okay and I can also delete this so
what I'm going to do is I'm going to show you how I can write unit tests on this
component specifically the app
component because I want to make sure that I am testing the logic of this list
of users okay I want to make sure that when I click on this button that I have
these input fields and when I click save
it's going to actually update the state of my username or it's going to actually
update the text in the document okay cuz
we want to test for behavior and not for implementation so the component under
test is going to be the app component so what I'm going to do is inside my Snapshot
well not not snapshot in my
test folder I'm going to create a new file called app. test. jsx okay and
again like wherever you are implementing this logic right over here so wherever
you are rendering user details uh that is the component that is going to be under
test which is going to
be app in this case okay so what I'm going to do is this I'm going to go
ahead and import my functions that I need from
vest so I need expect it and uh
describe so I'm going to go ahead and call the describe function and I'm just going
to call this
app and then I'm going to use the it function to create my tests so we'll just call
this should
render users okay and let's see so now we also need
the other functions we need render and we also need the screen objects so I'm just
going to copy this whole line and
whoops paste this right over here and we also want to import the app component as
well CU that's the component under test so let's import app
from uh app just like that we're going to go ahead and call the render function
and just pass in the the uh the app node the react node over here let's go ahead
and run our test let's see what happens okay let's
see here you can see that there is there are some errors already so we'll run npm
run test okay so uh let's see so I ran both
of our tests and then it failed on the app. test. jsx file it failed on this
test over here okay so what exactly is the problem well right now the problem that
it's telling you is that it's
complaining about this used navigate hook being called outside of a router
component and the reason why this is happening is because in previous sections when
we were going over the
react router uh we were actually wrapping the app inside the context of
our router which happened right over here and since we are rendering app
outside of the router provider and we're trying to use the use navigate
hook outside the router context that's the reason why it is complaining now I'm
going to go ahead and just temporarily comment this out because I do also want to
show you how we can write tests uh
with react router itself so I'm just going to comment this out temporarily and I'll
go back to this later okay so
I'm going to go ahead and Save this and what I'm going to do now is I'm going to go
ahead and type npm run test but I
want to actually only run the test on the app uh for the app file itself so
I'm just going to do app. test. jsx or you can use a regular expression and now
this will only run
test for app. test. jsx and now I can see it passes okay which is good I
believe it still makes the API call um which is another side effect that we
probably don't want to happen in our
test because what we want to do in unit tests is we want to simulate API calls
and not actually make a real API call because right now you can see that in our app
component we have this use fetch
user hook being called which of course is making this API call to the Json
placeholder API it fetches a user in a in a real unit test or in a unit test
you don't actually want to make real API calls okay the purpose of a unit test is
you want it to be fast you don't want it to actually make an actual real API call
because that could actually delay your unit test you want them to be fast okay
later on I'll show you how to use a mock
service worker so for now I'll actually just comment this part out and I'm just
going to comment out this whole
thing okay and uh I'll comment out user
data as well okay so let's just go ahead and make sure our test works
okay perfect so our app uh test works and let's just quickly I'm going to go
ahead and get the container one quick thing that you could do all the time to
ensure that your component is rendering
properly is you can use a snapshot test like how I showed you earlier on to verify
that the correct elements
are being rendered so if I click on this snapshot okay there you go you can see
that my user details component was
in fact properly being rendered because I can clearly see the username the email
address and the ID as well as the button
so this verifies that the elements are in fact being rendered to the document okay
I'm going to go ahead and just I'm
just going to I'll leave this alone for now okay so now what I want to do is I
want to write some tests right now okay what tests do I want to write so a lot of
times some people might be confused
with what to test so think about this anything behavioral wise on your
elements you want to test so what do I mean by that well in react testing
Library it focuses on behavioral testing not implementation testing so what that
means is you want to test for Behavior so in other words whenever you click on
a button what is the behavior after you click on the button so for example if I
click edit okay what is the behavior after I click on edit what is the expect
ation that occurs after I click on the edit button well visually as a user I
can see that a couple things happen I can see that the save button appears and then
I can see that uh two input Fields
appear that replace the text so for example the username uh has this ants in the
dev
field and then or this username field that has ants in the dev and then so there
this email field it has this email
address populated in there as well so that is the behavior that is the expected
outcome of whenever I
perform some type of action in the document okay now when it comes to
implementation details testing or implementation testing what that typically means
is you're trying to test
the underlying details of the component and not the behavior so rather than
testing that an an element appears in the document you're trying to verify that the
state of
a variable was modified okay so let's think about the code for a second let's
look at the implementation details right so in the user details component let me go
up top over here you
can see that we have some State I have this is editing State variable that's a
boen and you can see that when I click on this button what exactly happens well
when I click on the button the set is editing dispatch function is called called
which toggles the mode the it
toggles the is editing value from True to false false to true so if the value
was false now it's true if the value was true now it's updated to false okay so
when it when we talk about implementation testing what that means is you're
typically trying to test for
things like the value of the states such as okay am I verifying the state of is
editing is it false or is it true or what is the value of username what is the
value of email you don't want to
test for these implementation details because as a user you only want to be
concerned with what is actually being displayed what is actually happening to
the actual document itself right behavioral driven testing is a whole other
philosophy over implementation
details testing and the thing with implementation details testing is that
the implementation can change over time for example I might make changes to my
state variable is editing and the way that I render my uh the way that I
render my save button because right now the save button is only rendered when is
editing is true it's being conditionally
rendered the way that I might render my save button could change it could not be
based off of this state variable anymore okay and by testing for implementation I
have to also change the test over time as well whenever I change my component
logic but if I test for Behavior it decreases the chance of me having to test or
rewrite my test because we're
testing for Behavior so what appears on the screen I don't care about what the
state value of is editing is I just care about if this save button appears to the
document so hopefully that makes sense
if you have any questions or if you any clarification post a comment down below and
I'll be more than happy to explain
the differences okay let's go ahead and move on and let's go ahead and write our
first test so what I want to do is I want to write an assertion so let me refresh
the page what I want to do is I
want to write an assertion that whenever I click on the edit button the save button
appears okay so let's do this so
what I'll do is I'll leave this test alone and then I'll create another test down
over here because why not you can
create as many tests as you want and it's always good to test for different things
in its own individual test itself
self so what I'll do right now is I'll write a test and then I'll call this
test again you want to be descriptive well you want to be concise right you treat
it like this treat your test names
like a git commit message if you're familiar with Git which I'm sure many of you
are you obviously don't want to
write a whole essay you just want to write something short that describes what the
whole purpose of your changes
are so in this case I'm going to go ahead and keep it nice and simple I'm going to
go and say it should uh it should render save button
when edit button is clicked and this is you know short and simple okay it should
render save button when edit button is click and it's important to have your tests
uh the names make sense because
often times experience developers what they will do to understand a brand new code
base is they'll look at the tests
and they'll read it to to understand what exactly the behavior of each part of the
application is so for example if I didn't understand you know what this uh
react application was supposed to do I'll go into each test for a component
and I'll read the test itself and if I read this I'll say okay it should render
save button when edit button is Click so
that tells me right off the bat that if I go to this component on the screen when I
click on the edit button the save
button should be displayed and slowly this knowledge builds up and that's how you
become experienced with a brand new
codebase that you are not that you were not familiar with before okay so what I'm
going to do is first we always need
to make sure we render our app because in each test itself it's its own environment
right you have to always
make sure you render the component that you want to test so I'm going to go ahead
and render app but this time I'm
not going to uh do anything with the return value I just want to render it to the
document now remember that our app
component is pretty straightforward there isn't any complicated logic we have state
that is already defined with
a default value with one object in the array and it's just rendered to a document
there's no uh data fetching
going on we're not waiting like more than a second for our data to be rendered it's
almost it's almost as if
it's rendered instantly right and well I mean it's going to be rendered uh fast
enough that we don't need to use find by
Using getByRole to query Buttons
queries instead so we can actually just use get by so what I'm going to do is
I'm going to use screen get by and you're probably wondering well now which
get by query should I use should I use get by text and then pass in edit which
is the text of the button that I'm trying to search for right that's the text of
this uh edit button right over
here okay now while you could do this like you technically could do this right
let me show you uh the return value of get by text you'll see that when I use
get by text and pass in edit this will actually give me an HTML button element
uh right over here let me restart the test and you'll see that right over
here uh right over here it logs HTML button
element so we're basically searching for any element by the text and that element
could be anything in this case it just happens to be a button now while this
does work you shouldn't do it because there actually is priority whenever it
comes to certain elements that you're trying to search for so what do I mean by
that well according to the react
testing Library they actually have certain principles and they describe to you what
type of query you should use
based off of the element that you're trying to search for so for example uh right
over here you can see
that get by text is like number four out of uh I guess all five of these rankings
right so for example right now we're trying to search for a button okay in
case if you didn't know uh the button element actually has a r property okay
which tells you the purpose of the element itself what is the purpose of this HTM
element well the purpose of
this is a button so it's meant to be clicked on right so what you want to do
is you want to use the get by roll or query by roll or find by roll query
whenever you're trying to search for a button okay and it even tells you right over
here uh this should be your top
preference for just about everything there's not much you can't get with this uh so
like right over here get by
roll they show you an example of how to search for a button so you just literally
pass pass
in the r itself and then the text for the button and there's also this section
that gives you a bunch of different roles so for example you can search for buttons
checkboxes links menu items so
anything that has a rooll itself you want to use the get by roll that's like the
number one priority that you want to
pay attention to okay so let's go back here and what I'm going to do is I'm
going to remove this part and we're going to go ahead and call screen get by
roll and we're going to go ahead and specify the RO that we want to search for
which is going to be button again
there are a bunch of different ones so just pick the one that you ideally want to
search for in our case we want to
search for a button so I'll specify button and then now keep in mind that your
application the component that you're rendering may have multiple buttons
right in our case my component my user details component has two buttons so how do
I know which one to to search for
well remember that there was this second argument which was an options object and
the name property allows you to specify which button by the text you can search
for Okay so for example I can pass in name and what I can
do is it tells you that you can filter the return Elements by their assessible name
so in our case uh the edit button
the name of it that we can use is literally just edit okay the text of this button
itself okay so let's go
ahead and go back to our test and for the name I'm just going to set this to edit
just like that okay and now what
I'm going to do is I'll go ahead and just write a console log just to show you the
return value of this and since I
know that this button in fact does exist in the document this test is not going to
error
out let me run the test again okay and you can see right over
here it was in fact able to find the element okay you can see that we have a bunch
of different properties on this
element as well and it should show the text somewhere for
this button yep children edit that's the text of the button over there so that is
the correct button okay so what exactly do I want to do with this button now
well first let's go ahead and just copy this and I want to store this in a
variable so I'll just call this edit button cuz I possibly might want to reuse this
edit button over and over
again and then what I want to do now is I want to click on this button so this is
the part where I'm going to teach you
how to actually simulate events specifically click events on your
components on your elements so right over here what I want to do is I want to click
on this edit button we have the
element already we want react testing library to actually click on the button
itself so the way that we can do this is
as follows so what we want to do is first we need to actually install the user
event Library it's part
Firing User Events
of the testing Library API it's just kind of like a uh companion library is the way
that they describe it so by
default you don't have user event but you have to install it okay um it's
still made by the same creator of uh react testing library but it's just in its own
separate package Okay so so what
we're going to do is we're going to install this user event package so I'm going to
go ahead and type npmi hyen D
at testing hyen Library SL Usery
event okay and then the way that we're going to import it is like this import user
event from and then the name of the
package so I'll just copy this part over here and then what I'll do is I'll import
it like this so import user event
Simulating Click Event
from and then at testing Library user event okay so what I'm going to do is
I'm going to reference user event because this gives me a bunch of different uh
methods that I can use so
you can see by just hovering over this intellisense you can see that we have clear
click copy cut double click hover
keyboard paste pointer a bunch of methods and events that you can simulate
or methods that simulate events right so the one that we want is Click because we
want to click on on a button so user
event. click and then we're going to go ahead and pass in the element we want to
click on and you can pass in literally
any element you want it doesn't have to necessarily be an a button it could be like
a div for example so you pass in
that and then there are also options that you could uh pass if you need or we
don't need any for now now this click event is asynchronous it returns a
promise so we want to make sure that we handle that accordingly some going to add
the as keyword in front of my
callback function that I'm passing to the test and we'll await this call okay
so after I click on the button we can expect that the save button will appear
in the document right well at least that's what we can see when we actually
interact with the component itself and then that's what our test is supposed to be
testing for so when I click on the
edit button the save button should appear so we actually have to to write the
assertion for that now so again we
know how to search for buttons in our in our uh in our test okay we use get by
roll so what I'm going to do is I'm going to go ahead and do this const save button
equals screen get by roll and
then the r name is button and then now and for the name the name is going to be
save because that's just the name of the butt right over here okay and then what
I'm I'm going to do is I'm going to
write an assertion so expect save button and then we're going to use to be in the
document matcher okay so just to recap what's going on is first we are searching
for the edit button we click
on the edit button we have to await this call because it's asynchronous and then
after this has been clicked on we're
going to go ahead and search for the button uh the save button and then we're going
to go ahead and write an assertion
that that button is in the document we're not going to do anything with a save
button okay the whole purpose of this test is to just verify that the
save button appears so let's go ahead and see if our test actually works so npm run
test and
then I'll type in the test file name and let's see if it passes and there we go it
passes but what I'll do
additionally is I'll go ahead and negate the test to make sure that it in fact
was passing correctly so you can see that it says expect a document not to contain
element but it did in fact find
a button uh with the save name over here okay so this was passing correctly so
there we go so this test verifies the functionality of the edit
button so when I click on the edit button the save button appears and then this
test verifies that so we're good
we're done with this test we don't need to do anything more now obviously we still
want to make sure we're testing
other parts of this component because for example I want to make sure that uh these
input fields are also there but I
don't want to write all of that assertions inside this test because you want to
keep your tests clean and
concise you don't want to write like 500 different assertions in one single test
okay so what I'm going to do now is I'm going to go ahead and write another test
and this time I'm going to go ahead and
say it should uh display username and email in put
Fields when edit button is clicked
okay okay so there we go now one thing that I also want to mention is that
sometimes uh you might run into a hard
time where your name of your test it's hard to kind of like keep it short so
one thing that I like to do is I like to actually use another describe test Suite
inside my already existing test Suite over here so describe app and then
inside over here I have another test suite and then I can just label this test
Suite as uh something that groups
together uh similar tests right so what do these two tests have in common well
they have in common the behavior of whenever the edit button is clicked so what I
can do is I can say okay well
this test Suite is supposed to be for uh edit button okay so the purpose of this
specific test Suite is to basically tell me or another developer that's reading the
test that okay everything that's
within uh this test Suite has to deal with the behavior of edit button okay so
what I can do now is I can just copy these two tests and I can paste it inside here
and now I don't even need to
mention the edit button at all okay so uh let me do this uh I can remove let's
do this uh let's see edit button describe edit
button is clicked okay so describe edit button is
clicked should render save button so basically this test Suite the name of this
test Suite is allowing me to kind
of like prefix or describe each test that is occurring so it saves me you
know the ability to write like a long description okay so I'm shortening this
part and I don't have to mention the edit button because I'm inside this test Suite
which implies that everything that
I'm dealing with is the edit button itself so now I can go ahead and remove this it
should display username and
email input Fields so notice how now it's a lot more shorter okay so
hopefully this part makes sense so let's go ahead and actually continue with our
test so we'll go ahead and render our
app uh we do still need to search for the edit button so I'll do that right over
here and what I want to do now is I
want to click on the edit button so I'll do that as well so I'm just going to copy
what I had in the previous test because it's all
redundant and now this time instead of searching for the save button we just want
to verify that the username and
input fields are in fact in the document so the question is can we also
Querying for Input Elements
use the get by roll query to search for our input elements and the answer to
that question is yes you can now remember that according to the documentation the
official documentation
of rea testing library is the priority is get by rooll and then get by label
text is the second one so technically you should use get by roll over get by label
text to search for an input field
in case if you forgotten or didn't know that input Fields can have a label
associated with the input field itself for accessibility so when you click on the
label itself or if you hover over it
or if You tab to it and then you hit space bar it will actually focus on the input
field itself but not all the time
you will have a label text so I'll show you how we can do it by using get by
roll okay so here's what I'll do I'm going to go ahead and do screen get by
rule and the rule of our input field is text box okay text box just like
that and now for the options we need to make sure we specify which text text box
which input field we're trying to search for right because there's two different
ones there's this one and there's this
one they're both different so we need to basically filter it out
essentially so we can actually use this name property okay now this
actually requires us to set an ARA label on the field itself on the input
field itself so what we can do is this let's go into our user details component
and for this input field what I'll do is I'll set ARA label to username so that
way this will actually give the uh input field a name called username and then I'll
do
the same thing for the email input as well okay and you'll notice that when I
actually go into the browser tools so if you see right over here the name of this
input field this
username if I were to remove this Aro
label you'll see that the name is an empty string okay so we can use this AAL
label at the very least to search for the element by the text box if we don't
have a label okay but again like I said get by roll has a higher priority so you
should use that so what I'll do now is I'll set the name to match the name of the
input field that I want to search
for so that's going to be the value of this AO label so username and then we'll do
username like
that and if I go ahead and just cut this
I'll do expect paste that in there and I want to verify that this is in the
document so we'll do 2b in the
document and let's just see our test we can see that our test passes and of
course if this test if this uh screen uh get by roll call didn't find the text
box it would throw an error okay remember that's what the get by query does so this
test is passing if I were
to do not to be in the document it would obviously uh fail because it is finding
it okay so let's do the same thing for our other field so screen uh uh. get by
roll textbox and then the name will be email to check the
email field itself and there we go no errors with that whatsoever if I were to
pass an emails with an S it goes ahead and it errors out and you can see that
it actually gives you some decent I would say this is pretty good feedback so it
tells you the accessible roles so
you can see that we have our buttons and the name of the buttons are edit and then
for the input fields we have
username and email and that was set by the ARA label not the actual name attribute
itself okay so hopefully this
makes sense let me go ahead and just remove that and yep everything passes perfect
now as promised I will show you the alternative way to search for input Fields
whenever you have a label okay
getByLabelText example
now you could still use get by rooll because like I said it is a higher priority
versus get by label text but I
think get by label text is not a bad way I mean it's it's not it's not like it's a
bad thing to use get by label text
right because it is a lot easier to use get by label text when you do have it
that is so here's what I'll do uh so right now I am rendering a bold tag for
the username so why don't I do this why don't I conditionally render um a label so
if we're in editing
mode because remember this is editing State variable is what is uh is what is
allowing us to conditionally render the input Fields so when we click on the edit
button we're setting the state of
is editing to true or we're toggling it basically okay so let's do this when we
are in edit mode so when is editing is true instead of rendering the Bold
element which is what it's currently rendering we'll render a label so if is
editing I'll use a conditional uh I'll use a Turner operator for this uh so what
I'll
do is this if is editing is true I'll render a label otherwise I'll render uh
a bold tag right over here for username uh so we need the HTML 4 attribute and
that's just going to be the ID of the input field that I want to associate this
label for so username just like
that okay and then let me go ahead and just use the long syntax to
render this label so that way I can just do a username let me just see what that
looks like in
the document real quick okay username let me add a colon and a space as well
okay there we go and then let's do the same thing for email
address so let's do
this okay and then just copy this paste that there change up
the attribute value and then the name of the label okay so now if I look at my app
you can see now when I am not in editing mode so is editing is currently false it's
going to go ahead and just display
the Bold tag right over here when I click edit these are now labels and you can
verify that by just looking at the
document itself you can see we have our labels okay and notice how if I click on
this it'll focus on the actual input
field so what what we're going to do is we're going to use the uh get by label
text query to get the actual input field itself so this is what I'm going to do
I'm going to go into my test and I'm going to go ahead and
modify uh this call so instead of get by roll I'm just going to do screen. getet
by label text so what exactly is the label text
well it's literally what this text is over here so I can be very specific I
could do let's see we're trying to search for the username I do username
colon and the space you have to be very specific so I'll comment this part out
over here so watch what happens if I just did if I just did username okay
it's going to go ahead and fail unable to find a label with a text of username if I
did username colon let's see what
happens it passes so I guess it ignores the space it doesn't really care about the
space but as long as I have the
colon then that works okay and we can do the same thing
for email so I'm just going to copy this part over here and then we'll do email
col in like that okay there we go so we're able to find uh both input Fields
based on the label text and again if you want to be uh if you wanted to make sure
that your test is correctly passing okay you can even just modify just a little bit
and see what see what
happens to to the text or see what happens to the test so right over here I added a
space
and uh let's see what happens unable to find a label with a text of username colon
space I wonder if it trims the space itself because it doesn't seem like it trimmed
it over
here uh cuz if I were to remove the
space let me see there is a space over there
so not sure why yeah so I don't know I don't I wonder if it trims the
text but anyways so you can see that this works with get labeled text and
again if you have the opportunity to use get label text personally I would prefer
using get label text over get by roll um
but if you don't have a label then you you can just use get by rule and that would
be perfectly fine okay so
hopefully this part makes sense now before we move on completely with uh
Testing Multiple Elements of Same Instances
labels and input fields and searching for them I did want to show a situation where
you could possibly have
conflicting uh elements right because keep it mind that right now we're only using
one user that's being rendered to
the document and we only have one username field and one email field but what if we
had two users displayed to
the document and then both of those users are being edited simultaneously so I'll
show you an example So currently
I'll go into my user details component or not here but the app components and I'll
go ahead and just
copy this user and I'll just change up the data so I'll just set the username
let's do uh Michael so we have two users that are
rendered to the document right and then you'll see immediately that our test
actually just fail instantly because we're trying to find a button with uh
the name edit but it tells us right over here that it's not it's it it it found
multiple elements with the roll button and name edit okay so you can see
immediately that we have a problem so in
situations like this how do you ensure that you can set up your code in a way
that we can actually test it correctly because this is actually more so a problem
with the way that we are
rendering our elements rather than the way that we're writing our test keep in mind
that when you are writing tests
right the more difficult that you make your components the more difficult it
will be to test it okay so what we want to do to fix this well there's a lot of
ways that we can do this right like for example like if I wanted to what I could do
is I could use get all instead of
just get by right get all by roll get all by label text okay and then what I
can do is I can you know just write some assertions on all of the roles or all
the buttons to verify that they're all in the document but I have a better idea
what I'll do is
this I'll go ahead and for each button that I am uh
displaying to the uh to the document okay one thing that you could do and
Data Test IDs
again there this is one thing that you could do there there are many ways that you
can do this but one thing that you
could do is you could actually use a custom data test ID to verify which
button is which so you're able to distinguish each button for each user right
because we have one button for
this user or a pair of buttons for this user and then we have a pair of buttons for
this second user okay so what I like
to do is I like to set a data test ID so you can just go to the button or any
element and set this data test ID attribute right over here okay and then
what you can do is you can set the value of this so I can set this to anything that
I want but remember that you're
going to have multiple user details components being rendered okay which means that
you're going to have multi
multiple edit buttons that are rendered one for each user so what you can do is
you can actually uh do this you can do edit button or edit BTN
and then the ID of the user like this I will mention that something that you
should keep in mind is that you often shouldn't you should avoid using uh test
IDs um if you don't need to right because according to the documentation um you can
see that right
over here that uh get by test ID is actually the
last recommended query that you should use and they even tell you that you should
only use this where you can't
match by rooll or text okay or it doesn't make sense uh in example the
text is dynamic so if you can use get by roll you should so I'm only just showing
you this as an example I'm not going to actually recommend to prioritize using a
test ID over uh get by roll I'm just showing you this as an example okay so
I'm going to go ahead and give this a unique test ID because each user will have
its own edit button button same
thing with the delete button as well so I'll copy this attribute paste this here
and I'll just changes to delete button and remember that each user will also have
its own uh username and email input
Fields as well so we can also set IDs on their data test IDs on those fields as
well okay but before I do that though let me go ahead and go back to my test
and I'll go ahead and actually just just uh I'll comment this test out cuz I know
this is going to fail but I want to just
go back to this first test that we have inside this edit button is Click test site
so our test is still failing
getByTestId example
because right now uh we're still using get by roll but this time what I'm going to
do is I'm going to use get by test ID
instead and of course this requires us to know what the test ID is and remember
our test ID our test ID is going to be dynamic because we're using the users's ID
prefixed with a
hardcoded string edit button okay so if we want to verify that the edit uh if we
want to verify that the uh the edit button for the first user is in the
document we just have to do edit button and then the ID of the user which we know
is going to be one because we have
it hardcoded so what I'm going to do is I'll just do get by test ID edit button
one and then I'll do the same thing down over here screen get by test ID edit
button two and now you'll see that our test should uh pass but the snapshot is
failing um you know what I'm just going to go ahead and just update the snapshot so
now you can see that my test
is passing because I have everything hardcoded and if you look at the snapshot you
can see that everything is
uh obviously different now okay so like I said I would not recommend doing it
this way because one you're hardcoding this and again get by test ID has the
lowest priority and you should only do this if you cannot find the actual
element using any of these uh using any of these queries okay so only use get by
test ID if you just cannot match by the role or by text so now okay is there a
solution where I can search for each individual button for each
user well in the way that we set up our
uh in the way that we set up our UI no because keep in mind that without this test
ID there's no way for us to know
which butt is unique to the user right like for example if I just undo everything
right now remove all of the
um let me remove all of the test IDs okay let me undo everything that I
had in here if you were just to look at this right now you wouldn't be able to
tell which button is associated with which user unless if you were to you
know set the text of the button to include the ID of the user but obviously
you wouldn't want to do that because it just doesn't make any sense like the user
is going to be confused like why am I seeing uh the ID on the edit button it
doesn't make any sense right so there are there are different ways that you can
tackle this there are there are a
bunch of different ways that you can tackle um this specific uh this specific
problem now what I would recommend and again there are a bunch of different
solutions out there but I think one of
the best solutions that I would recommend is this so we know that the user details
component the amount of
times it is rendered is based off of the number of elements in this users array
okay so instead of associating a data
test ID with every single uh button because that's what we were doing before
and then same thing with the input Fields instead of doing that what I would
recommend is we can actually
associate a data test ID with the roots element of our user details component so
this div right over here I can add a data test ID to this and then I can just call
this uh
user details and then user. ID just like that so that way I am uniquely adding
this user details uh data test ID to each user details component and then
it'll look like this in the document you'll see user details 1 user details 2
and if there are 100 uh users it'll just go all the way from one to 100 right and
then what I would do is this I would query for the user
details uh I would query for the user details by the ID by the data test ID
okay so I'd query for the component by the user details ID and then I would use
using within() to search elements inside an HTML Element
the within API to query for my buttons
and my input fields in that specific element okay so I'll show you what I mean by
that so what I'll do is this I
still want these I still want these uh tests to pass so here's what I'm going
to do I'm going to make my I'm going to make my uh component a little bit more
Dynamic so watch this here's what I'm going to do okay I'm going to go ahead and
take a users prop into the app component and uh let me go and do this
uh user I'll call it users data and then I'm going to go ahead and pass user data
to the default state of use state so whatever I'm passing into app
as a prop which is going to be an array of users will be set as the state for
users itself so I'm going to copy this whole thing okay and then what I'm going to
do
is in the let's see in the in the entry point of my of my app where I am
rendering the app element so right over here in the router I'm just going to pass
users data like this okay and then
that will require me to pass this data in my test right over here so I
need to pass users for this I'll just pass an empty array because I I'm not really
testing for anything over
here and then let's see for this first test over here I'm going to pass users
data but this time I'm only going to pass an array with one element just like
that so that way my test is still passing cuz I'm going to have separate tests okay
so our test should pass let
me update the snapshot cuz that's what's feeling right now uh let's see what's
going on
[Music] here um what's going on oh it's because
I need to update this part
can I read properties of undefine reading map
um users data is complaining about something being undefined let me double
check my app components so we pass that in here which
is an array we know that it's going to be an array no matter what then users. map
uh
interesting I'm not sure why that is erroring out oh I'm sorry it's
failing over here users data sorry about that okay there we go I knew something
was wrong with the way that we did it okay there we go so we have users data set as
the prop and passing in this empty array over here I just I just
misspelled it should have been users data instead of users okay good so all of our
previous tests pass I don't want
remove this cuz I want to keep it as a reference so at least you all can still see
it now I will just
update uh a couple things what I'm going to do is because now we're dealing with
uh altering our mock data over here because right now this is mock data right and
we have different scenarios we
have a scenario where we have only one user but now we're going to write tests
where we have multiple users instead so
our our scenarios are going to be a little bit different so what I'll do is this
I'm going to go ahead and take my
whole describe and again you can have as many test Suites as you want you can have
you can
have an infinite amount of test Suite hierarchies so I can wrap multiple
describes within a describe and I think it's good practice because again you want
to be specific with what you are
testing and what what your scenarios are so over here I'll just
say um when describe uh I guess the best way that I
can uh give this name is uh let's see when users is only
one okay and then what I can do now is my tests are still going to pass and
then what I can do is this you know what I don't need this
snapshot anymore I'm just going to remove that because that's an unnecessary test
Suite so describe when
users is only one or when there is only one user I think that's a better
description and then now I'm going to write another describe when there are two
users okay so we're we're describing different scenarios and we're testing
different scenarios and again I think
it's important to test every possible scenario you can think about because this
will cover every single uh angle of
your application again you're not trying to aim for a 100% bug-free codebase
because there's no such thing as that there's always going to be bugs no matter
what you're just trying to reduce the amount of bugs that your application
could possibly be exposed to so even if you have a code base that is
99.1% bug free that is still fine okay again there's no such thing as 100% bug
free there's always going to be bugs so when there are two users and then what
we'll do is this our test is going to be
a little bit different this time so what we're going to do is we're going to go
ahead and
uh let's do this I'm going to copy that and I'll say
it should click edit button for first
user okay so we're going to go ahead and uh
inside oh I need to also call the render method as well so inside here I'm going to
call render pass in my app and again
we need to pass in uh the user data prop top but this time we need two users
because we have two users okay otherwise our test wouldn't make any sense right
so we'll do ID of two and then we'll do username Michael and then email Michael
gmail.com okay now ideally what you could also do is you can also have
another test before this one that verifies that there are actually two users that
are render to the document so
very quickly what I could do is this I can write a test should
have username it should have two users in it should have two users and again we
don't want to test we don't want to actually verify that the array has two elements
we just want to test the
behavior of the document itself which means that there are two there there are
users with two there there are two user
dreams display to the document okay one is ANS and Dev and the other one is Michael
so the best thing to do is first
let's let's render whoops let's render the app and then what I'll do is I'll say
expect and
Screen get by text and in the dev to be in the document and I'll just
duplicate this test for Michael
um yep Michael okay so this test should
pass okay let me update the snapshots because we don't have them anymore and then
notice how if I set
this to Michaels this will fail okay yep you can see that in the
actual snapshot or in the actual render itself you can see that we have uh
username Michael over here and then username Anson the dev over here okay so this
is kind of like an entry test like
you're verifying the most basic thing before you test any other behavior and that
is verifying that both users are
actually in the document okay now what I'll do is I'm going to test when I
click on the edit button for the first user so I'm rendering the I'm rendering the
uh app and then what I want to
do is first let me make sure that I have my data test ID I do so what we're going
to do now is we're going to use multiple different uh queries okay we're going to
use expect and we're going to do screen get by test ID and then the test
ID for the first user is just going to be what we set it which is a dynamic value
so it's prefixed with user hyphen
details hyphen and then the ID of the user which is going to be one for the first
user so we'll do I'll just
hardcode this user details one expect screen. getet by test ID and I can write
a bunch of assertions the first thing that I may want to do is verify that this
actually exists in the
document so I'll do uh user details equals that and then I'll do
expect user details to be in the document and then our test passes okay
great now this actually is a little bit redundant because uh get by test ID will
actually fail so we actually don't even care about you know writing this assertion
because this will fail if it
can't find it in the document so if I set this to three this whole thing will fail
so
writing this assertion is not necessary so I know some of you might be you know
eager to write a bunch of assertions but sometimes you can just skip writing
specific assertions just because we know
that get by will fail if it cannot find the element in the document so if this
doesn't fail it implies that this was able to be found now what I'm going to do is
I'm going to
use this Within uh this within function we're going to need to import that from
testing Library
Dom uh so let's go ahead and import that real quick we're going to go top over here
import from so at testing library and
then for slom like this and then we want to import within let's
see I'm not sure why that function doesn't appear um
in Intel sense but it should okay it is being correctly it is
actually part of it though I'm not sure why it didn't appear in intellisense but it
is actually there yep within okay so
what we're going to do is we're just going to use this within function and then
literally all we're going to do is
just pass in the element that we want to search elements from within that's
literally why it's called within so all
that means is we're going to search for we're going to query for elements that are
inside this user details element
which we got using the test ID so what I'm going to do is this within and then user
details and
you can use find by get by query by whatever it is that you want to use I'm
just going to use get by and then this time what do I want to get by well again
I'm trying to click on the edit button but you know this is not really a meaningful
test so maybe I might want to
change this to what we had above so it should click on the edit
button for first user and save button
appears it should click edit button for first user and uh this I I'll call this
and display save button okay so within user details so within the first user
details element that is rendered we're going to get the edit button by the roll
so get by roll button the name of it was edit
okay and then now what I'm going to do is I want to click on that button okay
so we're going to do this const uh let's do user or let's do edit
button okay and then what I'm going to do is
I'm going to fire an event so that's going to be asynchronous let me add the ASN
key word so wait user events and
then click edit button and then now what I want to do is
I want to verify that the save button appeared so what I can do is I can do
the same thing I can use within so I can use within user details get by roll
button name save and then additionally I can wrap
this whole thing with an expect CU I want to verify that this is actually in the
documents okay I know this was a lot but let's just make sure the test passes
so okay there we go you can see that the test passes so when there are two users
should have two users should click edit button for first user and display save
button okay so let's walk through this
step by step okay first what we're doing is we're rendering the app with two
users passed in for the user data uh prop in the array we first get the user
details for the user ID of one so that is going to be for uh ANS in the dev
okay and if you want to be even more specific you can literally use the within
query within user details and then you can do get by text and specify the
username to verify that it's Anson the dev and not Michael that we're working
with okay so uh let me do this get by whoops sorry about this it should be
within get by text this whole thing inside the expect and then to be in the
document and that passes um but though I do think a better I do I do think a
better test would actually asserting that Michael is not inside this user details
element because it shouldn't be
right cuz Michael should be inside uh the element that is associated with user
details 2 the test ID so what I'll do instead is I'll do within user details
query by text and then Michael and then remember we use Query by text uh to
assert that an element it's best used to write an assertion that an element does
not exist okay so within this what I'll
do is uh expect to be null like that
okay and then you can see that the test still passes because this in fact does
return null if I were to set this to be an the dev the test is going to fail
because it there is actually the text an in the dev so that's the reason why this
is not null okay so this asserts that we are in fact working with Anon to Dev and
not Michael okay okay now we get the button that has the name edit that is
inside this user details element which is associated with the user details one
data test ID which is for our first user ANS in the dev okay so we get that
specific individual button so it's literally just grabbing this edit button right
over here and then we click on
that button so we click on that and then the save button appears and then what we
do is within the user user details element cuz we're still inside the uh
the user details one element itself we verify that the save button is in the
document now you don't actually need to even use within at this point because
there's only one save button currently but if you want to be more verbose if you
want to be more specific you can use
within as well right like even if I did screen get by roll because there's
currently only one save
button right there's only one save button this would still pass but if you try to
work with a second
user you would need to actually use within because there are two save buttons in
the document okay so
hopefully this all makes sense so let me go ahead and just fix this back to have
within just so that we're more specific
and now you can see that we are able to uh handle the case where we have multiple
users rather than one okay and
if you want it to be even more uh Bo you can write a test to verify both users
okay so this one and then this one right over here okay so now let's go ahead and
actually do something with the save button right because so far we're just clicking
on things we're not actually
you know updating State we're not doing anything let's actually update the state by
clicking on the save button and
verifying that the username was updated right so let's go ahead and do this so
let's see should click edit button for first user and display save button so why
don't I write another
test uh let's do this it should edit second
user second uh it should edit second
username uh and save okay so I'm going
to go ahead and just add the Asing keyword for this call back function so this test
what it should do is it should
edit the second username and then uh and then save by clicking on the save button
and
then verifying that the username was updated in the document so there's a lot of
redundancy with our uh with our
rendering so what I'll do is I'll just copy this render this okay and then this
time what I'll do is I'll get the
the user details with the ID of two so screen. getet by test ID and then we'll
pass in user details too because we have two users and then what I want to do is
I want to grab the edit the edit button so uh what I want
to do is this I will go ahead and do within user
details get by roll button the name is
edit and I want to click on this button so um I'm just going to go ahead
and do this I'm not going to store the return value of get by roll in a
variable like I have been doing previously because we're only really using it once
so there's no point for me
to store it so I'll go ahead and do await user events. click and just paste
in this whole entire thing right over here because the the end return value is
whatever get by roll returns which is the actual button element itself so we can
just pass it in right over here so
we're going to click on the edit button then what I'm going to do is I don't even
care about verifying the save
button appearing because we already verified that in our previous tests so we don't
need to even we don't need to
basically assert that again okay there's no point for us to do that okay and
remember that by calling get by roll that and if it doesn't fail it pretty much
implies
that if it passes it implies that the button element was found so there's no reason
for us to assert that the element
exists because if it didn't it would just fail the entire test anyways because
that's what get by roll does or
that's what the get by query does so we we're going to click on the edit button
and then what I'm going to do is I want to uh Target the username so remember
the whole purpose of this test is to update the username I don't care about the
email field that can be for a separate test so I want to Target the
username field so this time what I'm going to do is I'm going to go ahead and grab
the username field okay now you
could get away with using screen and then get by label text and then
specifying the username field itself because currently Let me refresh right
currently or whoops sorry currently we
are editing the second user and there's only one user there's only one input
field for username right but again like I said you might have a point where you
might have two username fields in the document and in situations like that you
would want to make sure you use within to specify the user details component that
you working with okay so that's the whole reason why we're even using this within
uh function call in the first
place so you could get away with doing just screen get by lab text cuz there is
only currently one input field for
username and one for email but if you were to click edit for both users then
you would have trouble with that cuz now there are two username fields and two
email Fields so we'll just be consistent and we'll just use within so we'll do
within
user details then get by label text and then username
Simulating type event
without the space and then what I'm going to do is I want
to uh perform another user event so we're going to go ahead and do this
we're going to do await user event this time the event is going to be type okay
there are a bunch of different events for example you can paste you can cut
which just will get rid of all the entire text you can copy uh I believe the best
one that we would want is
probably type so user vent. type okay and then uh I'll just take this
whole thing within and then get by label text because remember this Returns the
HTML input element for us paste that in
there and then what I want to do is I want to specify the text that I want to type
so
keep in mind that uh we're actually just adding to the current value of the input
field okay so what I can do is I can just type something like uh one two
three okay so this will literally add one two three to
Michael okay so now let's go ahead and
continue so when I go ahead and type 1 2 3 in the label uh we want to make sure
we click on the save button so what I'll
do is this uh within we also want another
uh user events so await user events click and then within user details we
want to search for the the save
button I'm kind of just uh going through this a little bit faster because a lot
of this stuff is pretty much what we already covered already so it should be pretty
straightforward if you understood
everything before so within user details we're getting the save button for uh the
user itself that we're
editing so we click on that button and then now what we can do is we can write
our final assertion to verify that the text was in fact updated
and if you again if you look at it from an actual user perspective I click edit I
type 123 I click save and then now the
actual text should be Michael 123 instead of just Michael so what I'll do
now is I'll actually write two assertions I'll I'll assert that the username field
is not in the document
anymore just to make sure that that username field is gone after I click the tech
after I click the save button and
then I'll assert that the username the the new username is actually in the document
so first let's do this let's
do uh let's see uh within or expect within user
details we're going to go ahead and do query by roll button or I'm sorry not
button uh query by label text I'm sorry query by label text and then
username so we're writing an assertion that this uh this username input field
is no longer in the document So within query by label text to be null let's
verify that the test passes it does and if I were to negate this so do not. Tob
null it will fail because it's not act because it's actually null okay expect you
can see over here
expected null not to be null which doesn't make any sense right because null is
null null is not
null okay so there we go we're verifying that the username field is not in the
document that's great so now what I can
do is I'll go ahead and write another assertion within user details we want to
verify that the text Michael 123 is in the doc so let's do get by text Michael
123 to be in the documents let's see what
happens uh there we go so it seems like get by text uh Michael 1 123 is in fact
so Michael 123 is in fact in the document so it seems like the update was correct
notice how now if I just Tred to
do Michael it's going to fail because if you look over here it says unable to find
an element with the text Michael
and that's because the actual username is Michael 123 so I hope this
complicated test I mean it's not really that complicated but once you get the hang
of it it becomes easier right and
that's the reason why I'm showing you these different scenarios when it comes to
testing because the more difficult
scenarios you test the better you become at it so I hope that this helps you better
understand how to test your
components even when you have more difficult scenarios such as having you know Poss
possibility of multiple
elements of the same instance of the component appearing in the document okay
so I hope this all makes sense and we'll go ahead and move on to other
Other queries
examples now there are also a bunch of other different ways that you can query for
elements with react testing Library
so for example uh so far we've used uh get by rooll we've used get by label
text uh we've used get by text there's also get by placeholder text so for
example if you don't know what a placeholder is I'll show you very quickly so if
you have an input
field you can add this placeholder value and you can just type whatever you want
enter data and if you go to the document you'll see that we have our input field
and we have our placeholder value displayed over here and the moment that I type
something that placeholder value
disappears usually placeholders are useful to kind of like give a hint to the user
on what to type in there like
for example you see them often in a website that has a search box you'll see like a
magnifying glass and it'll say
search dot dot dot so that hints to the user that this is used for searching across
the website okay so for example
if I wanted to wrun a test to get an input field uh based on the placeholder
value you would want to use the uh get by placeholder text query okay again the
priority of this it's not really something that you would want to prioritize over
get by roll or get by
label text but like I said in your application not all the
time will you have a label for every single input field and sometimes you may not
be able to use get by roll so you
can use get by placeholder text okay so I'll just quickly show you a simple
example so what I'll do is this I'll go back into my components I'll create a very
simple component uh I'll just call
this uh test input field. jsx because I can't think of any other better name for
this component and I'll just go ahead and do
this give it an input
field okay and then I'll go into my test folder I'll create a new file call it
test input field. test. jsx and now we'll write a we'll write
our test so so first I'm going to go and just copy all the things that I need so
let's copy this um I guess that's it and now what I'll
do is I'll write you don't even need a test Suite sometimes you don't even need
a test Suite if your test is as simple as possible you can just easily just write
uh your test using the it function
I wouldn't recommend it because again test Suites are great for grouping test
together but you don't need one okay so
just for this simple example I'll just avoid adding one I'll just say should
find input by
placeholder okay and then what we'll do is I'm going to go
ahead and do this first let's render our component so
test input field going to have the auto imported with vs code right over here so
we render the input field and I'm going to go and just do expect screen get by
placeholder text or
whoops placeholder text and then what I'll do is I'll just
do uh enter dot dot dot enter data dot dot
dot and then to be in the document okay and let's go ahead and uh
let's see so our test passed it was able to find it notice have I removed these
three dots it's going to fail because we're using a literal string to fix that
you can use a regular expression like this enter data that way you don't have to be
more verbose and it's able to find
that input field by the placeholder value okay there's
also uh the get by display value which is literally the value of the input
field itself so for example see if I do value
hello and then if I go over to here well I guess I'm not rendering it right now
but I'll show you what it looks like when I do render it let me render that real
quick uh let me import that up top over
here from not sure why my intelligence is
messed up over here from components test inut field okay there we
go you can see that when I render this component I have test input Fields value
attribute set to hello so that is that is what's going to be displayed over here
now notice how I'm not able to
modify it if I try to type you can hear my keyboard in the background I'm trying to
type stuff into this input field
that's not being updated that's because we need to register an onchange events I'm
not going to do that just for this
simple example because I'm just trying to show you how we can search for the
element by the value the display value
so let me go into my test file and then I'll just copy this paste
this and I'll say should find input by display value so we'll render the input
field and then instead of using the get by placeholder text query I'll do get by
display value query whoops and then this time because we
have the value set to uh hello I'll just do that and then let's
go ahead and see our test and you can see our test passes and if I were to add an
invalid value it's going to go and
fail for that specific test the second one so hopefully that makes
sense now there are a bunch of other queries well actually not really there's
really just like a few more there's uh
get by Alt text which is for images well primarily for images you can use it for
images you can use for other
things too as they describe over here uh there's get by title um there is get by
test ID which we already covered and we just covered get by display value and get
by placeholder text so these are all
of the queries I encourage you to practice the other ones that we didn't cover
they're pretty straightforward and
just pretty much do what we've been doing so far in the tutorial uh practice them
and then verify that it was
correctly passing by just placing in a value that will cause a test to fail so that
way you know that you're not
dealing with false positives okay so that's pretty much it with all of these
different queries what we're going to do
in the next part of this testing tutorial is I'm going to show you how we can
actually uh test our components
whenever we have more complicated situations such as when we are using react router
or a context such as our
user context okay so stay tuned for that now in this section of our react
Testing Component with Context API
testing tutorial I'm going to teach you how you can test a component that depends
on the react context API so to
be more specific uh remember how earlier I commented out this whole user context
part so you can see that our post container component uh was wrapped inside this
user context provider so if
I take a look at the post container component you can see that uh it's literally
just a very simple component
it renders uh data that is coming from the context itself the user context
specifically I'll very quickly show you what the user context looks like so it has
an ID username email name and then
it also has this set user data function which is actually a dispatch function
which is used to update the state of the of a component that actually passes the
data down to the context level and that was what was going on in our app component
you can see over over here if
I were to uncomment this out and let me uncomment out all the other stuff such as
this user data State and the set user
data function that we have and let me uncomment out uh this use fetch user
hook call and let me uncomment out this use effect hook because this use effect
hook uh updates the state of user data so what happens is uh all of this data
right over here for user data and this set user data dispatch function they are
passed to this user context provider right down over here and in case if you
missed the part where we went over react context in our react tutorial go ahead and
check that part out okay everything
is timestamped but all that data is passed into the provider so that way any
component that is wrapped inside this user context provider in this case post
container will be able to consume the
context and access the data if I go back to my document if I go back to my
page you'll notice that right now if I refresh okay it's fetching the data once
the data has been returned you you'll see that uh it is displayed to the
document okay so we have post container and then all of the data right down over
here is rendered and that's perfectly
fine okay so what I'm going to do is I'm actually going to comment out all this
stuff again CU I actually don't need this this in order to write a test for it
because in our test we're actually
going to be passing the data as a mock data okay so you you'll
see in just a second so let me uncomment all this out because by leaving this I
think it might break our tests I believe
so let me actually show you if I rerun well it doesn't break the tests but it
allows uh these Hooks and all these side
effects to happen in the background which I don't want to happen so so I'll
actually just comment out all this
stuff and let me comment this
whoops comment this back and then let's go down over here and comment this out okay
so what we're going to do is we're
going to write a test for post container but this time what we're going to do is
we're going to wrap the post container inside our context and you'll see how that's
going to be done for our test so
what I'm going to do do is I'll go into my test folder and I'll create a new file
and I'll call this post container.
test. jsx okay now what I'm going to do is I'm going to import the same exact
stuff that I need so I'm going to import uh I guess let's let's import all this
okay and then what I'll do is let's see I guess what I want to test is I want to
test the name ID email and username are in the document Okay so so we'll just do
this describe um display
render context values okay and we'll write a bunch of
different tests to test for each to write assertions for each uh field being
rendered correctly okay so here's the
thing though when we render so let me first do this it should display correct
username when we render our post container
component right let's do that real quick so first I'll do render I'll call render
and then we want to render post container like this right now okay post container
itself again remember doesn't take any props all the data that is that it is
referencing comes from the context
itself okay now you'll actually notice that right now let me try to run this
test it passes but we're not reading any assertions right now it's not throwing any
errors
it's not complaining about it not being wrapped inside a context because currently
post container is just being
rendered isolated away from everything else it's not wrapped inside a provider
so when you go to try to write assertions well I mean we aren't even passing any
data to the context so like
how are we going to write assertions right and to even go a step further here's
what I'll do uh I'll show you the
snapshot I'll show you what it looks like in the default State when we're not in
the context like you're not going to get an error by calling the Ed context Hook
when you're outside of the
context but I'll just show you what the the document looks like okay let me save
so let me show you the snapshot you'll just see that it's just a bunch of it's just
all the default values that were
set right over here so you'll notice how zero is being displayed for the ID and
then all the other things that are supposed to be rendered such as the name email
username are not there
it's just all empty because it's an empty string okay and I'll even be more
specific let me go ahead and label this
with display name ID email and then
username let me save let's update the context or yeah I'm sorry update the
snap shot and now you can see that we have display name empty ID zero email
empty username empty okay so even though it's calling the use context hook it's
just going to give you literally this value but again what we want to do is we
want to actually pass values into the context provider for our
post container okay so this is actually how we do this is actually a lot easier
than you might expect all you you need
to do is literally just get the actual context provider itself so we're going
to import user context just like this and
inside our render function we're just going to go ahead and do user context.
provider like this and
then put the post container inside the provider it's literally the exact way
that we had rendered our post container wrapped inside the provider Ider now all
we have to do is just pass in the values for the provider okay so you just do
value and then you can pass in a username ID and then the set user data
function literally it's that easy okay here's what I'll do though I'll go ahead
and set up a fake user so const mock user and then we'll do ID we'll do uh
let's do 101 username uh
Johnny uh email Johnny
gmail.com and then name Johnny okay and then we'll pass in the
mock user like this and then we still need that set user
data um let's see actually you know what I'll do instead of doing this I'll
actually do mock user context data that
way I can set the set user data property right over here so I don't have to use
the spreader operator so for set user data this will just be a very basic function
that does
nothing and uh let me go aead and just take this and pass it as a value over here
okay so now I'm going to go ahead
and show you the snapshot let's update that snapshot because our UI changed you'll
see that in the snapshot you can
see the actual data that is in the context that we just passed
being displayed so I can begin writing assertions okay so I'm going to just
remove this uh I'm going to remove this part over here okay and then what I'll do
is I'll
just say expect screen. get by text and then we'll do let's see
Johnny to be in the documents okay and then let's just update this
this let's see what's going on
here uh oh you know what it is let me do username colon Johnny
instead there we go that passed okay um let's see I don't want to use a
regular expression because it's going to go ahead and it's going to go ahead and
search for it's going to match this
email address as well like if I were to use uh Johnny like this it would would pick
up email and our test would
actually fail cuz I found multiple elements that match this regular expression so
I'm not going to use that
I'm just going to do username uh colon Johnny and then we can just literally write
a bunch of other tests to verify
the other things were correctly rendered but you know sometimes you don't even need
to do that you can just literally
use a snapshot test to verify that the UI is being rendered correctly then you can
just look at the snapshot and just
make sure that everything is rendered correctly and again snapshot tests are not
useless
they're very useful for situations like this where you just want to verify that
basic data is being displayed so what
I'll do is I will leave this alone uh and then I'll just go ahead and write another
snapshot test I'll just
say it should render all I'll just say it should
match snapshot because it is the it is redundant for me to literally copy this test
multiple times and just verify
every single uh every single uh data email and name like it is redundant when I can
just look at the snapshot and verify that it is correct so I will go ahead and I'll
move this up top over here so I
can reference it again and then I'll render my data and then I'll go ahead
I'll render my component and then go ahead and get the container and do expect
container to match snapshot
okay and then let's update everything okay there we go I can just look at my
Snapshot verify that everything's good
and then we are good to go and again if I were to make changes to my post container
component my Snapshot would
fail and then we have to determine whether or not it was supposed to fail in other
words is the UI change supposed
to happen and if it's not then we have to modify UI to make sure we are not
changing it for no good reason okay all
right so while This Test shows you how to actually
verify data in the context is stored properly and you can see it from the
snapshot the question is how do we actually interact with our component
where we can actually modify the data in the context right because actually in
the post container component we actually did render this post content component
as well and then we also rendered the post content buttons component component and
what this post content buttons
component did was it actually updated the uh the name value in the
context so I'll actually just rerender uh post content
again so let me render post content and I need to import that again
so let me import post content
from post contents okay and then uh let's see we're not using data anymore so I'm
just
going to remove this prop and as you can see post content renders
post content buttons okay so let me just show you what was supposed to happen Okay
let
me refresh the page I do need to make sure post container is runed again so I do
need to uncomment all this out
and I'm just going to uncomment all this out for now because it's it's not breaking
our
other tests so I'll just leave it like that for now okay and all all of our tests
pass no
problem well the the snapshot needs to be updated because we made a change to our
user interface okay so all of our
tests are passing that's great okay you can ignore the warnings for now okay
wonderful so our tests are good so this was this is what was supposed to happen
Okay so right over here in the post
content buttons let me actually uh let me do this I should have done this earlier
let me change this to
an H3 tag and then let me change this to an H3 tag as
well that way it's easier for me to distinguish everything okay so right now
you can see that when I refresh the page you can see that I have my post content
component and then inside the
post content component I have post content buttons so what actually happens
is when I click on the click me button you'll see that the cont context display
name value was updated notice how it
says updated display name okay obviously not the most useful update but I just
did this as a very easy example to show you how this worked okay so what I will
do is I will actually add uh another input
field and I'll actually do this um I'll add some
State I'll call this value set value and I'm going to actually make it Dynamic so
I'm not just hardcoding some text that is meaningless so basically what I'll do
is I'll do this I'll bind the value to my state variable value and then I'll
register the onchange event
listener and then whenever the onchange event is invoked we'll call set value and
pass e. target.
value and then what I'll do is whenever I click on click me or I'll actually
rename this button uh updates or save display
name okay and then I'll uh set this to be value just like that okay and then
now basically whenever I type something into this text I'll say
Johnny and if I click save display name whatever I type inside this input field is
what will be uh reflected on this
display name or over here if I click if I type Johnny 123 and click save or save
display name it's going to go ahead and display Johnny 123 that that is how we're
going to test updating the context
now you're wondering well in our post container component for this set user data
function we just passed in this you know this empty function that does nothing so
even if we were to call set user data
it's not going to actually update the actual data in the context so here here's the
thing we cannot test the
actual update of the context from the post container itself we need to go one
step above and we need to basically go to the layer where we are actually rendering
the uh
provider with the component itself which in this situation that's our app
component because the app component has the US state call which is going to give us
the dispatch function that we can
actually call to update the state user data which will then in turn
update our context for us okay now the other problem here is that the user data
is currently updated whenever the the API call is done use fetch user so what
I'm going to do is this I'm going to go ahead and just comment out this use effect
hook and I'll comment out this
use fetch user API call I'm going to leave this use State hook alone cuz we
we will need this and the only difference is uh I guess what I'll do is
I can actually just pass in a hardcoded value so I just do ID uh
7,000 username uh Johnny display or not display name uh
email Johnny gmail.com and then
name Johnny Johnny the developer how about that so now what I want to do is I
actually want to write my tests on the app component instead of the post container
component itself because
obviously I can't just call the UST State hook inside my describe uh function right
over here
that's not going to make any sense and this set user data function is a mock
function so it's not going to do
anything even when it's invoked okay so we need to do it from the component that
actually defines the state that is passed into the context provider in our
case it is the app component itself for you it might be something else okay so just
keep in mind that whichever
component actually defines the state so in this case it's app then we need to make
sure that we are rendering the app
component and then writing our unit tests okay in this case it's more so of
an integration test rather than unit test because you know a unit test you're
actually testing an isolated component
just one individual component and an integration test you're actually combining
multiple components multiple
features together and testing them as a whole okay so what I'm going to do now
is this let me make sure that nothing is failing I do need to update some snapshots
okay so let me just make sure
all my tests are passing before we continue and yes everything's passing so that's
good uh okay so now what I'll do is this I'm going to go into my
app. test. jsx file and we're going to go ahead and go down over here and set
up another test Suite because right now this test is completely different than
all the other tests that we wrote previously okay so this time we're going
to describe updating user context
okay and again like I said this is just a very basic example we're only updating
one piece of information which is the
display name but you might have a more complicated form that allows you to
update different fields such as the ID email or username or all or all
three so what I'll do is this I'll just do I'll just set up one test it should
update display name
okay and now again if we look at our components okay we look at our if we if
we look at component we're dealing with an input field right so right off the bat I
need
to make sure that my input field is is actually queriable like I can actually look
for it so again earlier I mentioned
something where I said that writing tests require you to also set it up to
be successful right if you purposely go out of your way to set up your components
and your elements to be
difficult and impossible to test you're going to have a hard time writing a
meaningful test and writing a test that
can actually you know search for your elements and perform operations on it and
I'll give you an example okay right
over here in my post content buttons component which I know it says post content
buttons but I did add an input
field we we'll just go with it for now so this input field right over here I
need to be able to actually get this input field in my test right but how do
I get it because right now in the app component I have this other input field over
here so there's going to be a
conflict between knowing which input field to query 4 and especially this input
field doesn't have any other
meaningful data like it doesn't have placeholder text it doesn't have a default
value set it doesn't have an ARA
label okay so how do I grab this input field okay so again this is what I mean
you have to set up your components for Success right what I can do is is I can
either give this input field a label which is what I would prefer to do I think
every input field should have a
label that's just me uh you can also set an ARA label so you can query the label
by the by the uh name or you can get it by rooll and set the uh value of the AAL
label to the name however I'll just go ahead and use a label so we'll do HTML 4
and then we'll go ahead and just do this for the ID of this input field I'll call
it update this display
name and then pass in that as well for the html4 attribute and then we'll call
this update display name I I'll call it update name just to be more just to be
more simple okay update name and let's refresh page there we go that's our
label right over here okay so again these are things that you want to always make
sure you're considering and like I
said setting up your components for success okay and is there a reason why
your input doesn't have a label associated with it well I mean usually for good
practice you should associate
your input Fields with a label because it makes accessible accessibility for it a
lot easier right like I can just click
on this label and I can easily start typing stuff into the text box okay you
don't need a label but it does make life a lot easier when you have one okay
anyways let's go ahead and continue so what I'm going to do now is
everything that we've been doing before so we do know how to search for an input
field by its label text so we're going
to go ahead and first render the app component so render app okay now this time
when we
render the app component keep in mind that I don't need to actually wrap the app
component inside the provider
because the app component actually renders the components that are wrapped within
the provider okay before in my
post container component I had to wrap the render of the post container inside
the user context provider but in the app component we are
already rendering this post container inside the provider so we don't need to do it
anymore and all that all of the values that are passed in are already
defined right over here okay if you wanted to make this more
Dynamic what you could do is you can actually just pass you can actually allow the
app component to take the user
data as a prop and then just set that as the initial value kind of like how we did
for users data okay but I think for
this example we probably don't need to do that so here's what I'll do I'm going to
render the app and let's just make
sure uh let's see what's going on with our test
can I read properties of undefined map uh let's see what's going on here I
think it's a snapshot issue okay so one of them was a snapshot issue should update
display
name uh canot read properties of undefined oh yeah that's because we didn't pass in
the users data forgot
about that let's go ahead and do that we'll just pass an empty array because that
has to do with uh all of this stuff
over here we don't really care about that because we're not testing for that so we
can just ignore it and this is the
nice thing about writing tests is because you don't need to always passing the same
exact props for every single
thing that you're rendering okay so okay our tests are all passing but let's
actually write an assertion for this test because we didn't write any assertions
yet so let's go ahead and do
this uh we'll [Music] do uh screen get by label text
update Name colon so that's going to Target uh
this label right over here and give us this input field and then we're going to
use we're going to use this input field and we're going to fire an event
so we're going to use the user event. type method we're going to paste in that
element and then we're going to type uh we'll do let's
see you can literally type whatever you want I guess I'll just do um John Jonathan
the dev how about
that then we need to make sure we await this user event. type call because it's
asynchronous it returns a promise let's
add the asyn keyword in front of this call back and await this call and then we
want to make sure we click on the
save display name button so that will require us to buy another event so we'll
do a user event doclick and then we need the actual HTML element
which is the button to click on so screen get by
roll button and then the name of the button is literally just save display
name okay and then this is asynchronous so we await the call and then now we
want to write a test or you want to write an assertion to verify that uh
let's do this verify that uh display name colon
Jonathan the dev is in the document okay and uh I'll also do this um let's do
this uh let's see screen get by text
display name Jonathan the dev
okay and let's go ahead and run our test and let's see what happens so let's run
it again and you can see that everything passes and nothing fails so that's
wonderful okay and if I want to make sure that's oh wait actually I didn't even do
anything sorry about that got a
little bit too ahead of myself we actually need to write an assertion expect well I
mean you know like I said
if if this was actually supposed to fail like if it didn't find the
uh the text in the document this get by query would fail right remember get by
will throw an error if I cannot find it in the document so the fact that it didn't
throw an error is good but still
let me actually fix this real quick by doing expect screen. getet by text and
then to be in the document let's just make sure nothing
fails okay that's good and then I can just kind of like mess this up a little bit
make sure that we don't have any
false positives and you can see that it fails now because you cannot find this text
in the
document and then you can see right of here the actual display name is Jonathan the
dev okay so hopefully this shows you
how you can test updating the context
okay all right so now in this section of our react testing tutorial I'm going to
Using Mock Service Worker to Mock API Requests
teach you how we can actually simulate Network calls for our components that
need them so for example in our app component we were calling this use fetch
user hook a custom hook that we created that makes an API call to this Json
placeholder uh users endpoint and it gave us back a user now obviously we're
sick and tired of having to comment this out but like I said in a unit test and
in an integration test you don't actually want to call any real API you
don't want to actually make a real API call okay because again your tests are
supposed to be fast they're supposed to
give you instant feedback whenever you actually want want to actually call a real
API or if your API is calling a
real database you do that in an endtoend test okay we're not writing end to end
tests right now we're writing just basic unit tests and integration tests okay so
in a situation like this you want to simulate Network calls you don't want to just
get rid of them because your
components rely on them you want to simulate them mock the response so that way
your component can actually use that
data that is returned from the quote unquote mocked API call okay so I'm
going to show you how to do that we're going to need to use a tool called mock
service worker now I actually did a
tutorial about this probably like a year ago where I taught uh you all how to or
I taught people how to use mock service worker but um I'm just going to show you
how to set it up again because there's no point for me to just tell you to
reference that video when you're already watching this video okay so basically
mock service worker can be used in two different ways one you can use it for a
react application to Mock and well intercept and mock responses okay so for
example let's say you want to build your react application but you don't want to
worry about setting up an API just yet
because you're just probably not ready for it yet and maybe you're not a back in
Dev and you only want to focus on the
front end side of things so you can use a mock service worker that will basically
run in the background of your
react application and then whenever you are making requests using let's say the
fetch API or axios what mock service worker will do
is it'll basically just intercept those requests and then it will basically mock
the response and so it'll basically seem
as if you're calling the API but in reality the mock service worker is pretty much
like taking over that
request and giving you the mock response that you set up yourself so that's one
way they can use mock service worker the other way they can use mock service worker
is on the server side the node.js
integration well there's also react native as well we're not going to talk about
that but you can see over here on the sidebar there's the browse
integration which is what I just described okay and they show you an example right
over here we're not using
the mock service worker for the browser okay because we're actually making real API
calls you can if you want to but you
don't have to okay especially if you already have a real API endpoint for
development purposes that you can call for Local Host now if you go to the node
Jace integration you can see that this
node ja integration part is useful whenever you want to use a mock service
worker for node.js processes okay so in a situation where we are actually
writing tests this is the perfect example to use a node.js integration
with the mock service worker because what we can do is we can actually write our
tests and then we can set up a fake
server and then set up a bunch of fake handlers that will give us back our mock
response cuz remember that vest is
actually a no JS process okay it's not running although it is actually you know
simulating the JS Dom environment right like it's rendering the data to the
document it still is a nodejs process at
the end of the day okay so when you set up your mock service worker you want to
make sure that you setting up you're
setting it up for the nodejs integration so the first thing that we're going to do
is install mock
service worker so in the terminal just type npmi hyen D mssw
latest okay this will just install the latest version of mock service worker
MSW being the package name okay now what we're going to do is I'm going to go
inside my source folder I'll create a new folder called uncore Mox and uh let's see
I'll actually
create another folder called mssw and I'll create a new file and I'll just call
this I guess server. J yes and
then what we're going to do is import the setup server function from MSW and
notice how there's node and then there's browser there's also native as well which
I believe that's for react native
but we want it for node okay because we want to use this in the nodejs environment
so we're going to import
this setup server function and then what I'm going to do is I'm going to export a
variable called server and
we're going to call setup server and we need to pass our handlers okay so it's
an array of handlers but we want to actually use the spreader operator on it okay
so currently we don't have any
handlers and you're probably wondering well what are handlers well handlers refer
to the request handlers so that's
basically how you're going to set up your API routes for this mock server so
basically the way it works is you set up these fake endpoints that the server is
going to quote unquote l listen to so
whenever your react components are making a call that match the Handler
mock service worker will B will basically match that and then give you back the
mock response that's how it
works and I'll show you how to set up handlers so what I'll do is I'll create
another file and I'll call this
handlers. JS because I like to keep it separate and then all I'm going to do is
just export a variable called handlers
which is going to be an array and then we want to make sure we import
this HTTP from mssw and this is actually a uh
a constant that has a bunch of methods that we can call it looks like the expressjs
instance the app instance
itself so for example I can do HTTP Dot and then the method that I want to
replicate that I want to mock so what I can do is http.get and then I can go
ahead and simulate uh the routes so in this case what we want to do is we want
to actually provide the actual route that our component is calling okay so in
this situation right over here if I go to the hook uh use fetch user you can
see that the hook itself is calling this endpoint with a dynamic user ID okay now
typically whenever you use a mock service worker it's it's good good to use the
mock service worker for the
browser as well as the as well as for your test as well so for for good consistency
but you're not always going
to get that case cuz for example we're using an actual real API endpoint to get
the data so in the test I don't want to actually replace that API endpoint but I
don't want to actually call that endpoint as well in my test so I can just paste in
this whole URL I can also
just paste in the actual ID now we obviously don't want to hardcode the user ID
because it's Dynamic so what you
can do is you can actually use a wild card by just adding the asterisk instead of
the hard-coded ID so any API requests
made to this endpoint during our tests and with the dynamic user ID will be
resolved right over here so the second argument that we need to pass into this
http.get call is the resolver function
and it takes in one argument and the argument itself actually gives you a lot of
different
properties so I'll show you so uh this is what it's going to look like
resolver oops resolver just like that okay and uh I can actually just
reference this right over here and you can see that there are a bunch of properties
we have cookies prams request and request ID so um for example the
request property gives you an object that's it's identical to an actual request
object on the server side like
for example if you're using expressjs it looks similar to this right so if the
request itself had a form data
or if it had a request body you can get it from this request object if you wanted
to get uh request
parameters or the cookies you can get it from the resolver okay but uh what we want
to do is we actually want to return
a response okay we want to return a response and this time since we are
mocking this API call we can return literally anything we want we don't have to
return the actual API endpoint
returns but in order to be consistent with our application we should make sure that
we return the bare minimum that we
are using so in our case we're using uh let's see the ID username email
and name field so we should make sure that our mock response includes all of
those fields for that endpoint so what I'm going to do is this
I'm going to return and we're going to ref reference the response interface
like this this is part of the actual uh this is built into JavaScript then we're
going to call it Json okay and then what I'm going to do is I'm going to return so
keep in mind
that this API npoint it allows you to fetch the user by the ID right so let me
just show you real quick so you can see that I can fetch the user by ID one so
we should make sure we should also return the same ID that we are fetching the user
bu so what we can do is first
I'll actually just destructure the pams property from the resolver object
because I don't need the entire resolver object so for the ID I'll just set it to
prams doid because that ID is a route parameter and then we can literally just
send back whatever it is that we want okay so uh let's see I'm going to send
back the username we'll just do uh Josh name Josh and then email Josh
josh.com something like this right again just a very plain simple example now
let's go back to our setup server and what we want to do is first let's import
handlers from the handlers file that we just created and then we want to make
sure we pass in handlers but use the spreader operator on it
okay and that's how we set up our mock server okay that's literally it and
again if you want to add more handlers down the road you can so for example if you
want to mock post requests you can
do that if you want to mock put requests you can do that if you want to mock more
get requests you can change the endpoint
right and keep in mind that during your tests you can also override the handlers
which I'll show you how to do later on so in order for us to enable aable our mock
service worker for our tests
because we only want to use this for our tests again you can use it for your actual
react app if you want but that
involves a different setup so we're not going to do that we want to enable it for
our tests so what we want to do is
we want to go to our test or our setup tests file right over here okay and then
what we want to do is first we want to import this before all hook okay and
this before for all hook will be called the Callback function of it will be
invoked before all of the tests and what we want to do inside this before all
hook the Callback is we want to start up our server so our mock service worker
server so we're going to go ahead and first import the server that we created
from the uh server.js file right over here this is what we're
importing into the setup test file and then we're going to reference server. listen
just like this okay then
what we want to do is after each after each uh test what we're going to do is
we're going to go ahead and call server. reset handlers and then what we're going
to do
is after all the tests so let's go ahead and import the after all
hook we're going to go ahead and just call server. close because we obviously don't
want it open
and this will avoid memory leaks and stops requests in general okay all right
so let's go ahead and try running our
tests let's just make sure nothing breaks with what we're doing currently okay all
right so everything
is working just fine but let's actually write some tests that use the mock
service worker CU right now we're not really doing anything with this we just you
know called server. listen big deal
we're not doing anything with it so now let's actually go ahead and write some
tests that do that okay so how do we
actually write a test to successfully use our mock
server well first we need an actual component that is making an actual API
call that is matching our handlers so remember what I said earlier
we need an actual API call a get request specifically because that's the one that
we currently set up to this endpoint
with the user ID okay so we already have
that this app component currently calls the use fetch user or it doesn't we need
to uncomment it so let's uncomment it okay so we are invoking this use fetch
user hook and all it's literally doing is making this uh call right over here
this callback function okay and then it makes an API call to this same exact
endpoint that we are mocking okay and then it gives us the data back right over
here okay
so earlier I did hardcode my data right over here I hardcoded the user data but
we're not going to do that anymore okay what I'm going to do is I'm going to
actually remove all of this and then
what I'm going to do is I'm going to uncomment this use effect hook that I had
before that I originally commented
out in the start of this react testing tutorial and just to explain what's going on
basically what we're doing is
we are checking to see if we're not loading because remember loading is a Boolean
value that gives us the status
if we're loading or not so we want to make sure we're not loading we want to
make sure there's no errors so if uh error is a if uh if no error in this
case it's checking to see if error is uh falsy so if it's not falsy then this
whole thing will be true and then if user is defined okay so if this whole
condition statement is truy then that means we're going to go ahead and update set
user data we're
going to call set user data to update the state of user data and that is going to
be the data that is given from the
actual API server itself but remember we're using the mock server okay and we have
all all
of these variables as our inside our dependency array okay so now we're no
longer using well we're again we're still using mock data because we're mocking it
with the mock service worker
don't get me wrong we're still using mock data okay but at least this time we
can actually have our API call in the component without needing to worry about
it hitting the real server and we can still mock the data as needed okay
so now uh our context our user context is
going to have our user data state which is going to be the data that is coming
from the mock server mock service worker so let me actually run all the tests
again and uh let's just see what happens uh it's hard to kind of tell
right off the bat so we want to make sure that the mock service worker is in fact
being
used and right now let me see if there's any way for us to
tell cuz typically what will happen is at least in the browser side it will
tell you that certain requests are being intercepted but right now it's not
telling us anything okay so I think the best thing that we could do is this why
don't we do
this uh why don't I write an assertion
uh let's see because right over here we're just updating the user context okay uh
why don't I write an assertion
on the app component asserting that
the username uh Josh or maybe email Josh
josh.com is being rendered okay so let's see what does that look like uh email okay
yeah let's do that so
why don't I do that real quick uh let's do this
describe um rendering context data I
guess so what we're going to do is we're going to say it should render correct
email okay and then what I'm going to do is I'm going to render the app and then
keep in mind
that this time our data is not going to appear instantly it's coming directly from
the mock service worker though we
could actually delay it but I mean again we're using the mock service worker so
it's not actually calling the real API
so I think it should return almost instantly or or at least uh before the default
timeout is reached okay so let's
actually see what happens when I do expect screen get by text and then email Josh
josh.com let's actually see if the service worker is
working okay so right now it's not and you can see that everything is currently
empty so it seems like it is taking some time for the data to
display okay and that's okay so what we need to do is this instead of actually
just using get by text we'll use find by text okay so expect
and then we'll do await screen find by text because remember
this actually uh will search up to 1 second for the element itself and again
even though we might be using the mock service worker doesn't necessarily mean that
the data will appear instantly so
let's actually see what happens okay so 1 second has passed and let's see seems
like the data has not
appeared so this tells me that perhaps the service worker may not be actually
being hit and one thing that I can do is I can actually just set a timeout so let
me pass a timeout of 10 seconds or yep 10,000 milliseconds
and let's see if this gives us any more information okay so now our test actually
passes and it says okay it's able to actually find the text by email so I guess it
takes longer than 1 second for it to appear let me let me just kind of see if I can
uh pass in an invalid email okay so I pass in an invalid email
it's going to take up to 10 seconds because we set that right over here to find
this element by the text and it's
not going to find it because as you can see now the data is actually being
displayed okay you can see right over
here that we have yep so it seems like the actual data from the mock service worker
isn't fact being used okay
because you can see username Josh name Josh and then Josh josh.com are all being
used okay if I were to actually
remove this Handler if I were to remove the Handler and run the test
again you can see what happens it's going to take up to 10 seconds to search for
the text right over here and it
fails but if you look at the actual data all of this data is actually coming from
the real API itself don't believe me well just take a look at what is displaying on
our actual
component okay right over here and uh if I open the dev tools you'll see that the
network tab right over here this is what it is giving back the name username all
that stuff is literally right over here so this proves that when I remove that
Handler the server the mock service worker is not able to it doesn't match any of
the handlers at all okay so it just lets the real API get called but if I were to
set up a Handler
where I match the same exact URL then the mock service worker will
intercept that request made and we can change the return value so I hope that
this makes sense now one thing that I do want to do is I want to avoid modifying
the timeout so one thing that you could
do is this you can actually do a weight and
then use this weight four method that is imported from the react package it
didn't Auto Import for me but I'm going to I'm going to import up top over here so
you can use this wait for method and
this literally will allow you to pass a call back to wait for an element to
appear on the screen so this is a good this is good to use it with the uh
screen. find by text call okay so we can literally just do async and then uh
await screen. find by text and then uh what I can do is I can
actually remove this async keyword from this callback function actually I still
need it
sorry uh but instead what I want to do this time is this I want to
instead I want to do this instead expect to be in the document and we're going to
do it we're going to just put the actual real value that will be in the document
not the real value the mocked value okay so let's run the test again hopefully it
passes hopefully wait for will work
let's see what's going on here did it time out
let me see
um yeah it timed out I wonder if yeah I guess it takes too long I wonder if
there's a way to speed this up so I tried to do some digging and I
don't think there's a way to speed up the response from the mock service
worker um so what I'm going to do instead cuz I don't want to actually set
the time out manually every single time cuz right now right if I use a wait wait
for I can pass in an object to set the timeout to be
5,000 milliseconds and then the test will actually pass right over here you can see
that it takes up to I guess 3 seconds for the response to come
back so the best thing to do when you're dealing with with a lot of asynchronous
calls to like an API for example is just
uh set a global timeout and one thing that you can do so for example I don't have
to manually go to every single test
and set the time up to 5,000 milliseconds I can go into my setup test file and uh
there's a function called
configure that you can import from the testing Library SL react
package and then all you need to do is literally just call this function and then
you can just
set async UIL timeout over here and you can just set
it to whatever you want so I'll just set it to I'll set it to 4,000 for now you
can set it to whatever you think is appropriate for your application needs okay so
I don't have to worry about
setting this extra option anymore and let's go ahead and rerun
everything because we're making changes to the setup to set set up test file and
now I can see that everything
passes so yes it does take some time for the API to uh give back the response at
least the mock API okay um okay so hopefully this makes sense now I'm going
to show you an example where we can override the default handlers because right now
uh we have these handlers set
up over here and these are kind of like Global handlers right like they're kind of
like just default handlers that any
test can use but sometimes you might want to use a different Handler you may
want to return a different response you may want to override the uh the behavior of
said
endpoint right so for example you might want this endpoint to be mocked in a way to
return a 403 to handle uh that status
code so that way you can display a conditional message to the user saying that oh
yeah you're not
authenticated please log in these are just examples right so I'll show you how you
can override the handlers in real
time in the actual event of the of the test going on so this is how you can do this
okay right now I'm writing an
assertion to the document uh that this text email colon space Josh josh.com is
in the documents which it does appear after about uh 2900 milliseconds so what
I'm going to do now is inside this test I can actually reference the server the
mock server right over here okay and then let me first import
it up top over here so let's import server
from then we have to go into MOX mssw
server just like that okay then what I can
do uh let's go down over here okay then what I can do is inside
right before I render the app I can reference server and then what I can do
is I can go ahead and call the use method okay server. use and then I can
just pass in any amount of handlers I want that I need okay so let me just copy
this and let's see I do also need to make sure I import
uh the http constant from
mssw yep there we go let's go back down over
here and then I can literally add as many handlers as I want in my like I
said my app component only makes one API call so I only really need to just passing
one okay all right so
now I can go ahead and change the behavior of the of the resolver right so
I can go ahead and override the response. Json so for example I can
return a username of Joshua uh for the name I'll do Joshua
and then for the email let's do Joshua yahoo.com okay and now watch what
happens with my test you're going to see that my test should fail in fact it will
fail you can see now it says timed out okay because it can't find that specific
text where the email colon Josh jos.com is there okay and if you look over here
the actual text is Joshua yahoo.com okay so now you can clearly
see that we are manually overriding our Handler during the
runtime of our test which sometimes you might need to do because not all the time
you want to use the default
handlers that you set globally when you call the setup server function okay so
we can go ahead and modify our test and I'll just say uh email
Joshua yahoo.com that's the text that we're trying to search for and now our
test is going to pass after uh 2,000
milliseconds okay so I hope that this shows you how you can actually use the
mock service worker to literally intercept these requests and then return
a mocked version of that request again you can return anything you want so
another example is I can return an error if I wanted to so what I can do is this
instead of using uh response let me actually use HTTP response
instead um let's import that from the mock service worker package and we'll go
down over here and I'll return HTTP response dot uh error like this and uh let's
just
see what happens so we're responding with a network error and if we look in
our test you can see obviously it's going to
fail do it log anything don't think it does that's okay
but it's failing so it's not able to get the dat but again like I said our
application currently we're not
handling errors which we should but uh you can basically write like a custom
error message page so like if the data was failed to
load from the API you can just say fail to fetch something like that and then you
could test for that so again I'm
just trying to be creative and show you all different ways to return different
things so I hope that this makes sense and hopefully gives you some create ity
on how to test different scenarios now one more thing that I do
want to show you is you can also delay requests as well so I'm going to go
ahead and import this delay function from mock service worker and what I'll
do is right over here yep right over here uh first you
need to make sure that you're inside an asynchronous function so notice how I guess
I added this off camera but you
want to make sure you add the async keyword for your resolver function right over
here like that so
async and then what you want to do is you want to call the delay function that we
just imported and remember this is
asynchronous so you need to await this call it returns a promise and then you just
pass in the amount of milliseconds
you want to delay the request by so you can delay it by 2,000 and then basically
it will just literally just delay The Call by 2,000 Mill second so to show you
if I run npm run test I also did update my uh let's see where was it I
updated the async util timeout property to 5,000 just to let you all know and
then now you can see that it takes about 4,000 milliseconds for our app test to
finish specifically for this test uh I wanted to show the actual test itself let me
see if I can get it to display
because normally this test right over here takes about two seconds but now it's
taking I guess two seconds plus
another two seconds okay and notice how if I were to add uh let's say if I add
one more second I believe this will probably fail because it'll go over 5,000
milliseconds because it times out
at 5,000 yep there you go you can see that it took way too long and it timed
out so the API call failed so this is helpful if you need to delay requests
perhaps maybe on your frontend and you have some kind of logic where you are
going to cancel the request if after let's say 15 seconds a response was not
received from the API call itself so then you want to cancel it and then display
some kind of custom message
through the user and then you want to write a test for that so this delay function
is helpful for that case so
I'll go and just I'll just remove this cuz I don't really need it I just wanted to
show you all how that worked now in this section of our react
testing tutorial I wanted to show you a couple of examples on how we can write some
tests with our react router so
let's say for example we want navigation in our website and we want to make sure
that our navigation is working correctly
so in other words I want to verify that when I go to the base URL that this app
component and all of its contents are rendered when I go to the blog post page
all the contents of the blog posts page component are also rendered as well and
then if I go to the users page so this users pathway over here then all of the
content of the users page is rendered so
it's also an important thing to know how to test your application when you do in
fact use react router so I might to just
cover some examples and show you so this will require a little bit of a setup
process but it's not that complicated don't worry and I will also warn you that we
do have a navigation bar right
over here but the moment that I uncomment this app out all of the current tests in
our app. test. jsx file
it will actually throw an error the reason why is because currently the app
component itself is trying to use these link components and in order for you to
use these link components you need to be inside a router provider context which
currently by rendering app by itself it's not going to give us that router
provider context so what we need to do is we actually need to set up a custom
render that will actually render the router provider for us and then it'll
also set up a temporary or not temporary but a memory router and then that's how
we can actually render all of the correct routes with the corresponding
components so I'll show you what I mean so what I'm going to do is inside my main.
jsx file I'm going to
copy this array and I'm going to cut it and I'm going to go into the utils file or
utils
folder and I'll create a file called uh let's see
constant. jsx and then what I'll do is I'll export this routes variable and it'll
just be
my array right over here and then now I need to just make sure I import all of the
necessary Imports I'm going to
import app import the blog post page component and the users page component
right over here one thing that I do also want to stress is that since you are
dealing with jsx inside this file you
need to make sure that this is a jsx file and not ajs file extension
otherwise you will get some errors when you're trying to run your tests or any file
that will import this constant. jsx
file if you don't have that jsx extension and you're trying to use jsx it's going
to give you some weird issues
so just make sure you have have this jsx extension okay so now I'm going to go
into my uh main. jsx file and import that routes array that I just
created so this makes it more reusable so we're going to go ahead and import that
from
constants there we go so we're done with that and I can just remove all three of
these Imports we no longer need them so
what I'm going to do now is in I guess uh let's see inside
my tests file my folder I can go ahead and create a utils folder inside the
test folder CU we will need some utilities for our tests but most
importantly I'm going to create a file called I guess
helpers.com render so typically they call this uh render with
router and what we want to do is basically just render oh well there's two things
that
we need to do first we need to create a memory router so we're going to need to
import this create memory router
function so let me do that real quick so import create memory router
from and that comes from react router Dom and then we basically want to take
that rout array that we just moved into the constant file right over here and
then just paste it right over here we do need to import it of course so let's
import that and then we need to pass in
a second argument which is the options and then this is where you want to set
the initial entries so initial entries is an array and it basically just allows you
to populate the history stack so for
example I can do uh base URL
users blog posts things like this okay
and you can also set this initial index and then for example if you want
the initial uh entry the initial path to be uh this base URL you can just do the
index of that so that's zero if you want it to be users you can just set that to
one uh personally what I like to do is I
like to actually pass these in as options so for example you can uh have
your render with router function take in an object that has initial entries set
to an MD array or initial index set to
zero like this okay and then what you can do is you can just assign it
to this object right over here and it would work fine so the next thing that we
want to do is we want to import the
render function from the testing Library react package and then all we're going to
do
is just return render and then you want to render the react node so in this case
the only thing that we're going to render is the router provider and then set the
router prop to the memory router
we just created so this will basically just do what is uh happening inside our
entry point over here so you can see that we're rendering the router provider and
then uh the router prop gets passed
and then pretty much all of these routes that we have configured will end up
getting conf configured with the correct
path and then the correct component that relates to that path itself so the same
thing will end up happening when we
render this router provider it'll render all of the entries that we have set
up which is just going to reuse this routes array right over here and then we
should be able to just access each path
the only thing I don't like about this is that it doesn't allow you to get
immediate access to the individual
component so when you're trying to test your app component with a router you can't
pass
in custom props like this but then again though um in a realistic application
you're not going to actually pass in hardcoded data as props to this you know to
this app page
itself we need to eventually update this to have it fetch the data from an API
but for now we can leave it alone because that's not really an important thing to
fix right now so now I'm going
to go ahead and show you what happens when I do this so I'm going to just leave the
app. test. jsx file alone for
now and I'll just go ahead and create a test I'll just call this app with
router. test. jsx okay and then all I'm going to do is just import the custom
render this render with router file and then we need to import all the other uh
functions from vest and then we also want to import
screen and wait for well we don't really need wait for I'll import that if I need
it and then I'll remove the render
import because we're using render with router okay so now what I'll do is I'll
also use user event as well because we do need to click on stuff okay so I'm going
to go ahead and write a simple
test I'm not going to use any test Suite just because I want to speed things up a
little bit so I'll just go ahead and say it
should um it should render Navar and click
actually I'll do this it should click on users link and navigate to users
route okay bit of a long test name but that's okay for now so what I want to do
is I want to call render with router just like this and then you can set the
initial entries so what I'll do is I'll
set it to be just this base URL for now and then I'm not going to do anything
for the initial index cuz by default we have it set to zero so that's okay so now
remember that by setting the base
URL this base path it's going to go ahead and render the app component for
us okay cuz that's how we have our routes set up right over here so the first thing
that we are going to see or
not we but like the test Runner will actually be able to interact with are all of
the elements that are inside this
app component which is fine because we're going to go ahead and click on the Navar
links right over here I'm going to
uncomment this out for now okay I'm going to go ahead and click on this users link
and then I'm going to
write an assertion that will allow me to verify that the users dashboard text is
in the document okay so let's go ahead and do this so we're going to render
with the router we're going to set the base we're going to set the initial entry to
be the base URL and then what
I'll do is I'll write an assertion to verify that the user link is in the document
so the way that we can do this
is we can use screen . getet by roll and then the RO is going
to be link and then the name will be users like this okay and then I'll just say to
be
in the documents uh though I probably don't even need to write this assertion
because like I said get by roll will fail if it cannot find this so I'll
actually just immediately just fire the event on the element so I'll do await
user event. click so I'll just click on the link immediately and then what I'll do
is
I'll write an assertion and I'll go ahead and say okay uh expect screen get by text
and
remember that when we're on the users uh route I'll show you when we're
on the users route all it shows is welcome to users dashboard okay so all I'm going
to do is
just hardcode the text welcome to users dashboard just like this and then we'll
use the 2B in the document matcher and let's go ahead and run this test and see if
it works so in my terminal I'll go
ahead and just do npm run test app with router I only want to run this test file
for now and right now it's complaining it's saying expression expected so I was
running into this issue for like the
past hour so the reason why this is happening it has to do with our uh our
our name the file extension uh and I'll show you real
quick where this issue is coming from so I believe it's right over here yep
this should be named helpers jsx the reason why is because we are using this
route we're importing this routes array and it's using uh an object with jsx so
that's the reason why and if I save now I believe this should fix the error
uh let's see okay so it does fix the error but now it's going to error out with a
different thing and it's saying
that cannot read properties of of undefined reading path name so uh let me
see what's going on with this now it's complaining about this part right over
here create memory router initial
entries oh you know what it is I think I may have messed this part up I need to
actually pass an object and set initial
entries to this that should fix it okay there we go so now you can see that the
test passes sorry about that okay so our
test passes now notice how if I were to just change one little thing in the get by
text call and now errors out and you
can see that this verifies that we are on the user route because this entire
component this users page component is rendering with the H1 element with this
welcome to users dashboard
text okay so hopefully that makes sense and of course you can write a bunch of
other uh stuff if you want now currently
the users page does not have the actual um navigation bar but the blog
post page does so what I can do is I can write some tests to verify that we're
navigating successfully from the base path to the blog post path and then back to
the P base path so why do I do this
I'll go ahead and copy this whole thing and I'll just change up the name of the
test and I'll go in and name the test
this uh it should navigate to blog posts and back to base
path okay so the initial entries will set it to the base path so this time
what we'll do is we'll change uh the users to I believe it's going to be blogs
instead that's the name of the
link so we're going to search for this link right over here blogs and we're going
to click on it
and then now we're going to go ahead and write an assertion so instead of Welcome
to users dashboard it'll just be welcome
to blog posts page so I'll just hardcode that string right over here let's go
ahead and just run the test again make sure that part worked so it did okay and
these console logs I believe are coming
from the blog post page it's logging the state. posts or the state object right
over here and the window. history. state I just remove this because we don't need
to have that okay so we're going to go
ahead and write this assertion which we just did to verify that we are in fact on
the blog post page and then what I'll
do is I'll search for the home link click on it and then verify that the
welcome to blog posts page text is no longer in a document and that should be
pretty easy based off of what we've
learned in this whole testing tutorial so what I'll do is I'll copy this part
await user event. Click screen. getet by roll or still going to have the link
roll but this time the name of it is going to be home so we're trying to look for
this home link right over here and
then we're going to click on it when we click on it we're going to go ahead and
verify that the welcome to blog posts
page is no longer in the document so the way that we can do that is using the query
by
text function and then instead of checking to see if the element is in the
document we just verify that this is null so remember that query by text will
return null if it cannot find the
element in the document based off of this match okay so it is going to be null and
let's verify that by looking at
our test so let's run the test and you can see that it does pass and what I could
do is I can just go ahead and say not to be null and see if that fails and it
will fail because it is in fact null okay so yeah again like I said there are
many ways they can customize this um and like I said this render with router you
can always customize this to your need like I said earlier I don't like the way
that this is set up but this is what I
could find on stack Overflow as a good solution because the reason why I don't like
this because you don't have full
control over these um these uh components but like I said it doesn't
really matter because ideally in the actual real application I'm not actually
going to pass this hard coded data and in fact um I would actually just remove this
entirely this user data's array
this user's data array and then what I would do is inside the app component I can
fetch a list of users the same way
that I'm fetching an individual user and then when it comes to testing I can
actually just use the mock service
worker which I showed you in the previous section of this testing tutorial how to
mock the response back
from the API and then I can just basically store that data in some State
the same way that I'm doing it for the individual user itself and instead of
referencing this uh users right over
here which is just the data passed from this prop which is hardcoded I would just
reference the fetched data okay but
like I said you can always customize this you can find a bunch of different
instances on this render with router
function this isn't something that I came up with myself if you go to the react
testing Library docs they actually
have a page where it teaches you how how to actually create a custom render and
this is just one variation with it that
I believe is as basic as possible but I encourage you to customize it to fit
your needs so I believe that's pretty much it when it comes to testing with react
router
and that's going to be it with just testing in general so I hope you all enjoyed
this part of the tutorial and I
hope you enjoyed the entire tutorial in general if you've watched the entire thing
so I'll see you all in my next
episode peace out

You might also like