Hey guys, in this lesson, we're going to be creating a login flow. And very often when you're creating
these kind of screens you'll want to show different components depending on whether the user was logged
in or if they were logged out.
So for example, if they were not logged in and they go to your website, you probably want to show them
the login screen like this.
But if they were logged in then maybe you would want to instead, show a different message or a different
component.
And that's the goal of this lesson.
We're going to learn the techniques to show different React components depending on some sort of condition.
In this example, when the user is not logged in, we show them the login form, and if they are, we simply
just greet them.
This is what we're going to be building,
so head over to the Course Resources and get hold of the starting sandbox and then fork it.
All right.
So if we take a look inside the components folder, you can see that there is a single App.js. And
let's say that we had at the top here a variable, right? Called isLoggedIn, and we set it to false to begin.
And once the user goes through authentication, then this variable gets switched to true.
So what we want is we want to check the value of this boolean, isLoggedIn, and if it was true we'd render
this <h1> and if was false we render this form.
So how can we do this?
Have a think about how you might be to able achieve this with what you already know. You might have thought
of creating a function,
right?
So let's call it renderConditionally, and this function is going to check to see if the isLoggedIn
is equal to true,
but because this is simply a boolean which is equal to false or true, there's actually no point adding
this, and we can simply just check it like so.
But I'll leave it in for now to make it very, very clear that we're checking for a condition here. If
isLoggedin === true,
well in this case we're going to return a <h1> component,
right?
So I'm just going to cut that out from there and then return it here.
But else, namely if they are not logged in, or if this is equal to false, then we're going to return this
form component instead, like so. And then inside our div, let's just make it a non-self-closing div,
so sometimes when you hit Save in CodeSandbox it does these automatic formats which can be helpful,
but sometimes it's not.
And inside this div I'm going to open up a set of JSX curly braces and I'm going to call my function
renderConditionally(), and then add the parentheses to actually call it.
So now if we take a look at our website, it shows the h1, which is meant to say, "Hello".
And this is because our isLoggedIn variable is set to true.
Now if I set it to false, you can see immediately, instead of that, we end up with our Username, Password,
and Login form.
So this is one way of achieving this, but you can see we're doing it in quite a lot of lines of code,
right?
And it's not the most elegant. Given that this is probably something we're going to be doing quite frequently
in React, checking the value of a particular property and then rendering different components depending
on the value of that property,
there's some better ways that we can do this. To begin,
it probably makes sense to extract this form component into a separate component by itself instead of
leaving it as just plain HTML. Because this can be reused
and the thing you should always think about is that each component should have a single responsibility.
And this comes from something called the single responsibility principle which is something that's quite
central to computer programming. I'll link to this Wikipedia article if you want to read a bit more about
it.
But once you're done, let's head back into our sandbox, and I want to challenge you to create a new component
called Login which is going to contain this entire form component, and then create another component
called Input, which is going to contain each of these input components.
And remember that the inputs have different attributes with different values,
so you might want to use some props and make sure that you can reuse your Input component.
Pause the video and try to complete this challenge.
All right.
So it's always good getting more practice and getting more used to the syntax.
Let's go ahead and start off by creating a new file and I'm going to call that login.jsx.
And inside this file, I'm going to import React from "react", and then I'm going to create my function
called, Login,
and this is going to return that form component that we had from over here.
So cut it out from the App.jsx,
and finally, we're going to export this as the default.
Now
let me head back into my App.jsx, import my Login from "./Login", and instead of returning
that previous long thing, I'm going to simply return a Login component.
That's the first step completed, and I've extracted the Login component as a separate component.
Now the next thing was to extract an Input component so that we can reuse each of these inputs. So let's
add the boilerplate. And this input component is going to return one of these inputs from my form,
like so. And then let's go ahead and export it, and import it inside my Login. So now, instead of using
each of these separate input HTML components, I'm going to use my Input component that I created
myself.
And we have two inputs currently that we want to render:
one has a type of text,
the other has a type of password,
one has a placeholder of username, and the other has a placeholder password.
So both of these attributes have different values that we need.
So it makes sense to create those as props.
So we'll create a prop called type, and we'll create a prop called placeholder. Now the type for my first
input is going to be text and the placeholder is going to be Username. And then I'm going to have a
second input which has a type of password and a placeholder of Password as well.
So now I can go into my Input component, catch those props that's being passed over, delete the repeated
elements, and then change my type to use the prop.
So add my curly braces, and use my props.type and my props.placeholder.
Now if we refresh our website, it should look exactly the same, but we've now separated our concerns so
that we have the Input component which just deals with each of these input fields, we've got our Login
component which has an entire login form, and then we've got our App.js which has our conditional
functionality.
Now our code is a little bit shorter but not much.
One of the things I want to do is I want to be able to carry out this functionality inline,
so at the place where I need it to be rendered namely, pretty much here.
But notice how if I go ahead and delete where I call my function renderConditionally(), and instead I
copy and paste my if-statement into here,
it's not going to work.
I get an error.
And the problem is that, remember when we use JSX, everything that goes inside these curly braces must
be an expression,
and this is not an expression.
This is a statement.
So if you recall back when we first introduced JSX, I recommended watching a video which explained
the difference between expressions and statements. Statements perform some sort of action and common
examples of statements include loops, switch statements, or if-else statements.
Think about the ones which have a keyword. In contrast, an expression just resolves to a single value.
Wouldn't it be nice if we could convert our if-else statement into an expression so that we can use
it here?
If only we had an expression in our JSX that still has the same logic namely, checking if our user is
logged in or not,
well, luckily for us Javascript has something called the Ternary Operator.
The ternary operator looks something like this,
it's got a condition which we define such as is sky == blue? Or in our case, is that variable
isLoggedIn equal to true?
And then we have a question mark, and after the question mark we say, well, do this if it's true, such
as render the h1. And then after a colon, we get to specify what it should do if the condition was false,
such as rendering our Input component. So for example, I live in London,
so whenever it's cloudy it's probably going to rain.
So internally, I probably have a ternary operator in my brain which says if isCloudy is true then bring
an umbrella,
otherwise bring sunscreen. So the syntax comprises of the question mark and the colon and putting the
conditions and the expressions in the right places.
And that really is the beauty of this syntax, instead of a statement,
we now have three expressions. The condition is an expression, bring umbrella is an expression, and bring
sunscreen is also an expression.
Therefore the whole thing is also just an expression.
Let's go ahead and have some practice with this.
In our case, the condition is this one right here that we're checking in our if-statement. And then the
thing to do if it's true, is to create a h1.
And the thing to do if it's false is to create a Login component. We can refactor this if-statement
into a ternary operator like this.
First, we have our condition which is being checked, which is this one right here, and then we add a question
mark.
Effectively you could read this as, "isLoggedIn true?"
Well, if so, then let's create a h1 component. And then we add a colon, which means everything that comes
after the colon is what to do
if it's false.
So return a login component instead.
And now if I simplify this and bring it all onto one line then you can see it looks like this. If
isLoggedIn equals true, render a h1,
if login is not true, then render the Login component.
So if I switch this now to a true, you'll see I get the h1 being rendered instead.
And if this was false, then it starts rendering that Login component. And in fact, I can simplify this
even more because this itself is a boolean.
We can simply evaluate whether if this is true or false and we don't even need this check.
So try it out yourself and see this ternary operator in action. Now
sometimes you might not want to render anything at all if a condition is not being met.
Let's say we create a const called currentTime, and we set that equal to new Date(), which gets the current
date and time, and then we call that function getHours(),
and this if we log it, should now be equal to the currentTime. So in my console, it's reading 13 because
it's 1 o'clock.
Now let's say I wanted to show the user a message depending on that time.
I'm going to go ahead and comment out this line of code, which you can keep around for reference. But what
I want to do is let's say if the currentTime was after 12 o'clock, if the currenTime was greater than
12,
right?
So right now it's 1 o'clock.
Then I'm going to ask the user, "Why are you still working?" So let's say I want to show this h1
"Why are you still working?"
And I wanted to show it as long as the time is past 12 o'clock.
Clearly we're not working very hard here, are we?
So how do I do this?
Well, I could check to see if the current time is greater than 12,
this is my condition.
In that case, so add the question mark, I'm going to render this h1, but if it is less than 12 then
I don't want to show anything at all.
So I could achieve that by simply adding that colon which defines what it should do
if this condition is false, and I'm going to show nothing at all.
I'm going to set it as null.
So if I set my date to, I don't know, 2019 November the 1st, at let's say, 9 am,
then it's not going to show anything on screen because this condition is not met. But as soon as the
time changes to past 12, let's say 18,
then it says "Why are you still working?" This way
we're able to render a component if this condition is met, and render nothing
if that condition is not met. But there's actually an even easier way and a shorter way
using JavaScript, and it involves the AND operator. We know that we can use the two ampersands (&&) in JavaScript,
like this, where we have expression, and another expression, when they're both evaluated if they're both
true, then this entire line of code turns into the value true.
Now, let's say that I had a variable which was x, x happens to be equal to 5
at this moment in time.
Now if I was to use this syntax EXPRESSION && EXPRESSION, then it might look something like this, Where
I'm checking if (x > 3 && x < 7), then go ahead and do something.
And if one of these is not true, then don't do anything at all.
This is usually how you would use the
AND operator in JavaScript code, as well as other languages.
Now this case is easy because when x is 5, 5 is both greater than 3 and less than 7
so this overall expression evaluates to true. But what happens if x was equal to 1 instead?
Well, 1 is not greater than 3.
So that first expression is already false.
And so to save time, JavaScript doesn't even bother evaluating the next expression, because as long as
one of the expressions is false where an AND operator is in use, then the whole line is equivalent to
false.
So a lot of React code leverages this fact and we end up with something that looks like this. On the
left-hand side,
we can have a condition, and then we have the two && for the AND operator, and then on the right-hand
side we have an expression which will be evaluated as long as the condition is true.
But if the condition was false, then it's not going to evaluate the right-hand side at all,
so it's not going to be carried out. As an example over here,
instead of using this ternary operator and passing null when this condition is false, we can simply delete
the ternary operator and just add two ampersands here.
This does exactly the same thing.
Let me explain why.
So the current time is 18 hours or 6:00 PM. When the code runs down to this line, it checks 'is 18 greater
than 12?'
Well, that's obviously true.
So it goes ahead and evaluates the right-hand side of the
AND operator. And this line of code actually gets carried out and put onto the screen. And in React
that means it gets rendered. But if this left-hand side of the ampersand was false, let's turn this to
9 o'clock again.
But because the AND operator requires both sides to be true,
if the left-hand side is already false then there's no point even looking at the right-hand side.
So this right-hand side basically gets skipped. And in React,
that means nothing gets rendered
which is the same as null. Depending on your own level of comfort with this line of code,
you can choose to use it but you don't have to.
You can achieve the same thing using the ternary operator and a null for the false condition.
But out in the wild when you see a lot of React code, you'll see people using this a lot.
Don't get confused,
they're not trying to check if these things are both true,
they're actually trying to render something only when this left-hand side condition is true.
All right.
So now that you've seen the theory, in the next lesson you're going to be applying it yourself and tackling
a challenge to be able to use the ternary operator and the AND operator.
So all of that and more, I'll see you there.