Support Multiple Views in a Single Page Application with @reach/router

Andy Van Slaars
InstructorAndy Van Slaars
Share this video with your friends

Social Share Links

Send Tweet

From a user perspective, navigating your application should be the same whether its a server-rendered PHP app, or a single page app written with React. To avoid breaking known paradigms for our users, we want as link to behave like a link. A view change should come with corresponding updates to the browser's address bar and the back button should work as expected. In this lesson, we'll install @reach/router and set our application up with a second view that we can navigate to with a link. We'll also verify that the browser's back button works.

Instructor: [0:00] Right now, all the logic and markup that renders this form and this list of cards lives directly in our root app.js component. I'd like to support a second view where we can practice our flashcards. Let's do some refactoring so that we can support multiple views in this application.

[0:15] We'll start by adding a new file to our components directory. We'll call this cardList.js. Here we're going to import React from react. Then we're going to export a function called cardList. cardList is going to take the existing UI that we have in app.js and return that. Let's go to app.js. I'm going to scroll down to my return here.

[0:44] We don't want the entire thing. What we want is everything that currently exists inside of main. We're going to grab the H3 and this div that contains our form and our cardList. I'm going to cut this.

[0:57] Back in cardList, I'm going to return. For now, we'll add a div. Then we'll paste everything inside of there. This div is because we need to have a single return element. The H3 and this div are siblings, so this would cause an error.

[1:12] Now we have cardForm and cardPreview being referenced in here, so we need to import those. We'll import cardForm from cardForm. We'll also import cardPreview from cardPreview. We'll save that.

[1:35] Back in app.js, we're going to want to replace the markup that we removed with a reference to cardList. Up at the top here, we can get rid of the import for cardPreview and cardForm. Then we can import cardList from components cardList.

[2:00] In order for this cardList component to work, it needs to know about cards and our handler functions, like handleRemove, handleAdd, and handleUpdate. I know that our other view for practicing the cards is going to need to know about the cards. I'm going to leave all that state up here in app. I'm just going to pass it down into cardList.

[2:20] We'll come down here. We're going to pass cardList a cards array which will just reference cards locally. We're going to pass it an onAdd, which is going to be our handleAdd. We'll also pass it an onUpdate, which will reference our handleUpdate function. Finally, we'll give it an onRemove, which will be our handleRemove function. We can save app.js.

[2:49] Then we can go back into cardList. We can get all these props. We'll just destructure them. We had cards onAdd, onRemove, and onUpdate. Now I just want to update the references here, so onSave here. Instead of this handleAdd, it'll be onAdd. We'll have onUpdate, onRemove. We can save that.

[3:14] Now if we check this out in the browser, we should see that our app is still working. All of our state updates work as expected. We can add a new card. We can edit that card. We can delete that card.

[3:34] Now let's add the component for our other view. I'm going to go to components. I'm going to add a new file. I'm going to call this practice.js. In here, I'm going to import React from react. I'm going to export a function called practice. For now, it'll just be a placeholder. We'll return a div with the text "Practice here." I'll save that.

[4:02] With this in place, I'm going to go into the terminal. I'll quit the app. I'm going to install Reach Router. I'll just use yarn add. That's @reach/router. We'll let that install.

[4:19] Back in app.js, I'm going to go to the top of the file. I'm going to import Router from reach router. With Router imported, I'm going to go down to my render. Right inside main, I'm going to add this Router component. I'm going to put my cardList inside of it.

[4:45] Router will go through all of its child components. It'll augment them. cardList is now going to have a path prop that we don't have to define, but we are going to pass it in. We're going to tell it what path to render on. We're going to render this on the route path. With all that in place, we'll save this.

[5:02] We'll run the application with yarn start. When this reloads, it'll make our API call, and it'll render out our cardList. Everything is still working as expected, but now we have the router in the mix. Now we can come back. We can import our practice component.

[5:19] Here at the top, I'll just import practice from components practice. Back down where I have my cardList, I'll add an instance of practice. I'm going to give this a path. This will be /practice.

[5:41] In order to get to this, we're going to need a link that'll send us to this URL. I'm going to go into the cardList component. Right under my H3, I'm going to add a new div. I'm going to give this a class name of practiceCTA, for call to action.

[5:56] In here, we want to put a link, but we're not just going to use an anchor tag. We're going to import a link from Reach Router. We'll import the link component from Reach Router. Then here we'll use our link component. We're going to give it a to prop. to is going to point to our /practice path. We'll give it some text.

[6:24] Now if we switch back to the browser, I've revealed the address bar here so that we can see this work. When I click this practice deck link, it's going to add /practice to the URL, and it's going to show us our other component. The back button will also work. All this happens client side, so no round-trips to the server for these page changes.