Introduction to Render Props in React
Now that we know our login process works and hopefully we have a little bit of a better understanding on how authentication works in general.
Guide Tasks
  • Read Tutorial
  • Watch Guide Video
Video locked
This video is viewable to users with a Bottega Bootcamp license

Now we're gonna start building out the full authentication process starting at the app component level, so at the very top parent component level so that we can manage authentication in every page of our entire app. So, let's kinda mimic and see what we're looking to do 'cause I think it helps to see the final version and hopefully, that will be able to clarify what our goal is.

So I'm here in the finished application and as you can see right here, we have a sign out button and I have these links that are only going to appear if the user's logged in. So if I click on logout, the links disappear and as we've seen before, the routes themselves are also completely gone.

So it has the NoMatch route if we try to access one of those. And that's a behavior we're looking for, we don't just wanna hide the links, 'cause that's not very secure, we wanna make sure that we're also completely blocking the route itself.

So, if you think about the best way to do that and I'll switch back to our application. If you think about the best way of doing that, it's at the app level. Because if you look through it, you can see in our Switch statement, we have all of our route definitions here.

And so what we're able to do, imagine a scenario where I just deleted one of these, say I deleted the Contact route. It would no longer exist, if I hit save, right here and come back. We still have this Contact link here because we have that in our nav bar, but If I click on it, and let me hit refresh really quick, there we go.

Now it says, we couldn't find that page. So, come back, test it again. So, it's catching that NoMatch route, which is exactly what we're looking for. So our goal is going to be, to mimic that. Obviously, we can't go and delete code but what we can do is we can add a conditional process.

So, certain links, such as a portfolio manager and a blog manager link, those sets of links, and those routes should simply not exist if the user is not logged in. And so, we're going to start at the app level, so that we can control that.

So the very first thing that I'm going to do is going to be right at the very top of the class definition. And, so I'm going to start by adding a constructor, and we are going to be taking props in, and this is gonna be something we're gonna go through over the next couple of guides.

Because in order to pass props and to receive props back through a route, we're gonna have to implement something that is a little bit more on the advanced side but it's very cool and very helpful for whenever you're wanting to get data back from one of these routes.

So we'll walk through it, but we're gonna take a very methodical, step by step approach, so it'll take a few guides to do it. So, we're first going to bring in super and props, just like any of our other class definitions that need to be able to work with props, and then from there, I'm gonna declare a starting state.

So, I'm gonna say this.state and then inside of the state object, I'm gonna give it a loggedInStatus and I'm gonna start with a string and say NOT_LOGGED_IN. Now, there is no reason why we need to have caps lock or anything like that.

The reason is because this is following a convention that whenever you want to establish some data point that you're gonna use as a conditional in JavaScript, this is a pretty common process to follow, so that's why I'm doing it. We're gonna have two states, we're gonna have not logged in and we're going to have logged in. Now if you're curious on why I wouldn't do something like this, where I'd say something like loggedIn and then false.

The reason for that is simply because JavaScript can be a little bit confusing with conditionals that check for boolean values. Meaning that I might perform a check and say something like, Okay, is the user logged in? And it might say true but in reality, it might just be finding an empty string or something like that and that is really, really a great way to introduce bugs into your application.

So what I'm going to do is to be able to have a hard defined value for NOT_LOGGED_IN and then we'll also have a string of logged in, that way whenever we run a conditional to check to see if a user's logged in or not, it's gonna be very apparent if that is the case.

app.js

this.state = {
    loggedInStatus: "NOT_LOGGED_IN"
}

So, that's the first thing and then from there, I'm going to go and build out a few handlers. So the first one is going to be handleSuccessfulLogin and this is not gonna take in any arguments, it's just gonna be a regular method. And when this is called, I'm going to update the state, so here, our LoggedInStatus, and I'll just copy this, our LoggedInStatus is simply gonna be LOGGED_IN and then we also want to check and have a handleUnSuccessfulLogin state, so handleUnSuccesfulLogin, just like that.

And, in this case, the loggedInStatus is going to be NOT_LOGGED_IN. So how are we going to be able to use these methods? Well, that is where we're gonna get into a very cool concept, which is the render prop. So we know about render, render is the method that every single class inside of React needs to have in order for it to be a class component and we know about props, so props are like path and component and things like that.

Well, what a render prop is, is a render prop is passing a prop to a component but actually being able to communicate with the render process. So that may seem a little bit confusing and I know it was confusing for me the first time that I used it. So I think one of the most helpful ways of understanding it is just actually seeing the code.

So let's actually build this out and I'm gonna give us a little bit of room 'cause we're going to write a decent amount of code. We're gonna keep the same path prop, that is gonna remain the same. And if you're curious about how we know how to do this, this is all in the React Router documentation.

So, if you simply go and go to react router and find that, then you'd be able to come to all of this beautifully formed documentation, here I go to the web, and you can see that we have a lot of different options.

I highly recommend, I think I mentioned it earlier, but I highly recommend going through the React Router docs, you will learn all kinds of great things and see how powerful of a tool it is. So that's how I found out how to use render props and how I could pass props to one of the route components.

So we have this route and we're gonna keep the path here but we're not gonna keep this component. And the reason why is because we're going to, instead of just saying, hey route, here is the Auth component, instead we're gonna say hey route, we're actually gonna take care of defining the render process for you.

So, instead of just defining a component, the prop I'm gonna pass in is actually called render and then from here what I'm gonna do is pass in props, and let me actually just stay on that line, so I'm gonna say props because what render takes in is a function.

So I'm gonna say props, which is the first argument. And then from there, I'm going to tell it exactly what we want to render, which in this case is the Auth component. So, after the fat arrow function then I want you to add parens and from there we're actually going to call the Auth component, just like we would call a regular component. So I'm gonna say Auth and then from here, I'm gonna pass in props to the Auth component.

So the very first one I'm gonna pass in and this is gonna look weird if you've never seen it before. It's curly brackets with a dot dot dot, which is the JavaScript spread operator. And so, what we're doing, is we're going to spread the props that we're getting passed in from render.

So there are already a set number of props that are getting passed in, like path and those kind of things. And that's gonna be passed in, so we're gonna have access to that. And then from there, we can start defining the values. So we wanna pass in our handleSuccessfulLogin and so from there I'm gonna say handleSuccessfulLogin= and then this.handleSuccessfulLogin which is our method that we already created and then I also wanna pass in handleUnSuccessfulLogin, which is the other one we created, just like that and then make sure you close off that Auth component and there we have passed in an actual render prop.

app.js

<Auth
  {...props}
  handleSuccessfulLogin={this.handleSuccessfulLogin}
  handleUnsuccessfulLogin={this.handleUnsuccessfulLogin}
/>

So, I know this part can be a little confusing. What we're getting into here is actually a little bit more advanced than typically you'd get in one of your first React courses. But I think this is so helpful for understanding the render process, how you can work with it, and also how you can work with props. And so, if you do not understand all of this right now, do not worry, we're actually going to be stretching this over a few guides.

And so hopefully by the end of that, it's gonna make sense. So what we have here, just in review, instead of passing in a regular prop, like path or something like that, we're also passing in a render prop. So we're overwriting the render process. Here, we're getting access to the props, which is the first argument in this function.

<Route
  path="/auth"
  render={props => (
    <Auth
      {...props}
      handleSuccessfulLogin={this.handleSuccessfulLogin}
      handleUnsuccessfulLogin={this.handleUnsuccessfulLogin}
    />
  )}
/>

And then we're saying, hey inside of this render, I want you to call the Auth component and that's what I want you to render. I want you to allow it to have access to all the props it would have been given anyway, like Auth and those kinds of things. But then also, I want to override it and pass in my own set of functions, my own types of handlers.

Now in order to not have any errors, we also have to bind these handlers to the constructor and bind them to this. So at the very top of the constructor, I'm gonna say this.handleSuccessfulLogin = this.handleSuccessfulLogin.bind this, and then just do the same thing for handleUnsuccessfulLogin, and then the same thing here, handleUnSuccessfulLogin.

Okay so, what we have here, is not, we don't have anything that's going to work yet because we have not wired this up with the Auth component, but I think this is a good time for us to take a break right now because this was a lot of code to write and some pretty advanced concepts.

And so I don't want you to feel intimidated if you do not understand this perfectly yet, the reason is because it's very hard to understand this part of the process, without understanding what it's connected to. So hopefully what is going to help you really understand the process that's going on right here, is when we go into the Auth component, and then we have access to handleSuccessfulLogin and handleUnSuccessfulLogin and then we can have a two-way communication type of situation here.

So our Auth component can update this method and when it updates this method, what it's gonna do, gives us the ability in our parent app component to manage our state. So we're doing all of this, it really boils down, to be able to have the access to say, loggedInStatus NOT_LOGGED_IN or LOGGED_IN. And from that point, every other component that we have in our entire application will know if we're logged in or not, and then it can adjust accordingly.

Resources