2.3 Adding Navigation
Naturally, we need to be able to navigate through our application. In this lesson, we'll install React Router and set up the navigation between our post list and individual posts.
1.Introduction2 lessons, 12:37
2.Getting Started3 lessons, 34:33
3.Fetching Other Data3 lessons, 27:16
4.Authentication4 lessons, 47:23
5.Conclusion1 lesson, 01:14
2.3 Adding Navigation
The previous session we wrote two components for displaying our posts. The first was a list of posts, and then the second was an individual post. But one thing we did not do is have the ability to navigate between our post and the individual posts. And so we are going implement that in this lesson. Now one thing that we haven't talked about is the dependencies for this application. Now, you might have looked at package.json and seen what they are, but it's really quite simple. As far as the application is concerned, we're just relying upon react and react-dom. That's going to change in this lesson because we are going to add a react router dependency here. But everything else are dev dependencies, things that we would use for developments, but they aren't really used for the application itself. So the first thing we're going to do is add react router. And we have several packages that we could choose from. But there is one that is specific for the browser, and that is react-router-dom. So let's go ahead and let's say npm install. We want to save this, and that is react-router-dom. And there are two routers that we could use. One is called a browser router, and that would be ideal to use, except that you need to have a server that will generate the HTML, or the markup, for the individual pages. So that if you make a request for one of those resources, the server will generate everything. But after that, everything is done inside of the browser. Well we dont' have a server side component in this case. So we're going to use what's the called the HashRouter, that's going to change our URL so that it relies upon the hash. So, let's first of all start in our app.js. Now let me also say that we are going to refactor a lot of our code. And as I was planning this I had thoughts, should we go ahead and write it correctly the first time? Or should we emulate real life and write our code so that it works and then start to massaging it to get it how we want. And opted for the latter because, as I mention, that's how we write applications. Very rarely do we write something correctly the first time. Or the second or third. It takes a lot of time in order to get our applications how we want them. So we're going to import a few things from the react-router-dom. The first is our HashRouter, the second is called Switch, and then the third is called Route. And we're going to be using some of these in our other components as well. And this is of course from react-router-dom. So here inside of our app components we are going to be changing this somewhat. Because our other components, the post-list, and the post are going to be state full components. That's how we have to make this work because we can't really pass data from one component to another using react-router. And we really don't want to do that anyway, as I will demonstrate later on. So the first thing we're going to do here is change our usage of PostList. Instead we're going to use our Switch component, given to us by react-router. And we're going to set up the routes for those components. Well, it's really setting up the routes for those components. We're setting up the routes for the URLs that are going to be handled by the components. So our first route is going to be an exact route. This is going to be our root. And whenever display our roots we are going to display our PostList. So, our path is simply going to be a /, that's home, and then the component, the handling this route, is going to be our PostList, so let's go ahead and use that there. Now our second route is going to be for displaying an individual post. The path is going to be Post, and we're also going to have the id. And we're going to get this id as a parameter whenever it is handled by our Post component. Now we are not exporting our Post component, so we're going to need to change our code right now to make that happen. So let's go ahead and change our imports here so that we are importing both the PostList and the Post. And then we will head over to our PostList so that we will export both the Post and PostList. So we need to get rid of this export default. We're also going to change this code to be classes as well. And we will definitely come back here, but let's go back to app.js, and we need to do one other thing here. Whenever we call the render method on ReactDOM, we aren't going to render just App. Here we need to include our HashRouter. So that is going to be wrapping around our app so that we can set up routing within our application. Now, the only thing other change that we're going to make to this class is taking out the constructor as well as the componentDidMount method. So our App component is going to be pretty simple. We are just going to have the render method where we use the Switch, we set up our routes, and that's it. So we're going to head on over to our PostList, and we're going to change this to a class. And we're going to put that code that we just cut out of App into PostList, because PostList is going to be responsible for retrieving our list of posts. And then the Post component will be responsible for retrieving an individual post. Now that sounds inefficient, and really it is, but since we are doing everything within the browser, that's how we have to do it. If we were going to be able to use the server to supply the markup on what I'm going to call hard requests, that's where we type in the URL in the browser and go directly to a resource, then we wouldn't have to do it this way. But since we are creating essentially a single page application and everything is going to be within the browser, then we have to do it this way. So changing this to a class is going to be relatively simple. The body of what was the function is now going to be the body of the render method. So let's go ahead and wrap the render keyword and all the other method stuff around that, and then we're going to paste in the constructor as well as the componentDidMount. However, when it comes to the render method, we don't have props anymore, we are now using state. So we're going to change this up a little bit differently. And we could also change the usage of the Post component here. And let's go ahead and do that just so we have a difference in terms of what we see in the browser between the PostList and our Post. So here we are still going to be building our posts, but instead of Post, let's use an h3 element to display the title of the post, as well as a link. So we're going to change this to this state, and then posts.map, and so on and so forth. And then we will have our h3 element. And we are going to keep our key property here, because we still need that. We are not going to pass in all of our post stuff as props to this, but we are going to have a link. This is where we are going to set up the link between our PostList and our Post. So we are going to need to import link from react-router-dom. So let's go ahead and do that. We want link, and that might be it. We can always come back and add more. Okay, we want a link here. And we are going to use the to property. This is basically going to say that we want to go to something. Now, we can pass two things for the to property. It can be just a simple string, which would be our URL, essentially. Or we can pass an object that would have some more information. It's more of a descriptor object. In our case, all we really need is the URL, or the path, rather. So that's what we're going to have. We're going to have Post, and then we're going to pull in the ID for our Post. So we would just say, post.id. And that is going to be it for the value of the to property. Then we are going to have the title for the text here. So we will say post.title and we need to use the rendered property. And that is going our link. So overall it's mostly the same. We are still displaying at least some of the information that we were before, it's just slightly different mark up. And of course we are using state now to keep track of our posts. So now let's focus on our Post component, and we're going to start with the same thing. We're going to change this to a class, that of course extends React.Component. The body of what was this function is now going to be the body of the render method, so let's go ahead and wrap that code with the render method. We'll align that. And we also need a constructor here. And we are going to make a request for our individual post. So let's just copy what we have for our PostList because that's going to give us just about everything that we need. Now as far as our state is concerned, we don't need posts, in fact we don't really even need the entire post object unless if we wanted to work with all of that data. For right now though, let's do this, let's have a title, and let's go ahead and initialize that as an empty string. We'll have our content and we will do the same thing there. And of course we can add more properties as we need them. So that is going to be the state that we are going to keep track of. So when it comes to actually rendering this, we are going to not use our props, but let's do this. We will say, let post = and we'll say, this.state. That's not really a post, but that gives us an easy way to access the title. And what we'll do is go ahead and get the rendered property whenever we retrieve the data from our API, we'll just use the rendered property as the value for our title and our content. So let's change this code so that we use the Post variable there and now we just need to make a request for an individual post. Now, right now, our API just allows us to retrieve all of our posts. But, what if we did this? We could say that we want to also pass in an id. And if we have an id, then we will of course append that to our URL. And that's all we have to do in order to retrieve an individual post. The path of that is still going to be the same, except that we are going to add in the id at the end. So if id is not undefined, then we are going to append that to our URL. And that's all that we have to do. So we'll say URL += '/$(id)'. That's all we need there. That will retrieve an individual post. So, that's inside of our Post component. We need to get the id. Now, we get that id. If we go back and look at our route, because of this here, we have a parameter. So whenever we react-router routes this, I'm going to call it a request, to our Post component, it's going to give us the id that was used here. So let's go back to PostList, and we get that id by saying, this.props.match.params.id. It is a mouthful, and a lot to type, but that's what we get. An of course we want to set the state. So that we will say that title is going to be data.title.rendered. And content is data.content.rendered. So, this should be it. We will find out in just a moment. So let's go to our command line. We want to say, npm start, to start the dev-server. We will hop on over to the browser. And let's refresh the page. Now notice that the URL has a hash in it. And if we go just to the base, or the root here, it's going to automatically append to that hash. So this is the HashRouter at work. Now of course we're not seeing anything here. So we probably have an error, and we do. We see that API is not defined, and that is because we did not import that here inside of our PostList file. So we'll say import. We want Api from and then './api'. So let's save that again. Let's look at the browser. And our error goes away. And we see our new list of hosts. So if we click on either one of these, then it should take us to the individual post. And it does. This is the second post. So we can go back, we can click on Hello World! And then we see the post there. Now earlier I showed you why we want these individual components to be responsible for retrieving their own information. Let's go back to our code and inside of the PostList. And when we retrieve our data, and we set the state. Let's do this. We're going to say console.log('in post list'). So whenever we save this and we go back to the browser, now notice we don't see that message here. If we refresh the page we don't see that message. That's because we are making a request for an individual post. And so our application is just showing that post. It's not loading the PostList, because it's not needed here. So if we had retrieved all of our posts with the PostList, and we passed that information on to the individual post components through the router. If we could do that, which we can, it's just not very feasible to do. Then we wouldn't be seeing anything here, because the PostList wasn't loaded, so we wouldn't have that data in order to view this. So if we click on back, well that's going to take us back to the PostList, and now we see that message because now we need the PostList that is of course going to be used. So that is why we wanted to retrieve not just the PostList, but also the individual post. Because not every request is going to be made for our PostList, so we wouldn't have that data to work with. But now we have, I'm not gonna call it a fully functional application, although it kind of is, but it still really isn't complete. There's still some information that we might want to display here. Like the user who wrote the page or any of the categories that the post is using. And we will get started with that in the next lesson.