React Routing and State 3 ways: part1

jared stevens
8 min readOct 21, 2016

For a long time now the standard React application has been using Redux and React Router, two great tools that were not built to work together. If a developer wants to use Redux and React Router together in their application it requires them to bring in middleware, specifically react-redux-router. But it doesn’t end there, Redux itself is not specifically designed for React. While this doesn’t mean you can’t use vanilla Redux with your React app, it does make it a bit more verbose than we generally like. So we bring in react-redux to be the connection which elevates the verbosity. So now to build or application we have no less than four separate libraries, not counting Async calls in Redux that require yet another library. This is starting to remind me of another problem we all hate: ‘Callback hell’.

There are many libraries starting to stretch their legs and challenge this standard. Libraries like MobX, Reflux, Elm etc. Some of these libraries differ greatly from the Flux/Redux style, while some libraries like MobX are very similar, but give the developer more freedom in their code.

This blog post is the first part in a three part series. To start this journey we will build a very simple two page app that takes in an input on one page and displays it on the next one and we will do it purely in React Router. In part2 we will rebuild this same app in Redux with React Router and then in part3 we introduce a new library called Desklamp that aims to make this process cleaner and grounded in react from the start.

So let’s begin with the React Router build.

The front page of our application will be a simple Home page that displays a header reading “Home”, renders a nav bar and a paragraph tag.

To start we create our index.html file and basic html page with a div to hold our React component.

As you can see we are pointing a script tag at bundle.js this is the bundled file of our application. I am using webpack to compile and serve the application of course you don’t have to use weback it’s just my compiler of choice. If you’re not familiar with webpack and you want to learn more, here is a link.

Now that we have our index.js file we can start building our application. At this point it is a bit of a design choice whether you build the components first or the router first. Personally I choose to build the router first, this helps me think about my application and what the structure of it will be. For our application the router will look like this…

Let’s break down what’s happening here. To start with we import all our required items. The interesting ones here are the react-router imports. Router is your router component it takes in your separate pages and allows you to route to them. The Route component does exactly what it sounds like it creates a route out of your component. It does this through the use of prop pass-ins. The path prop will be the name of your new Route and the component prop is the React component that you built as the top level component for this route. If we look at the Page2 route you’ll notice that we have a /:user on the back of the route path, which is a route param. We are using them just like you would use routeparams in an HTTP request, we will discuss this param usage a little later. The final route with path=”*” is there as a catch all basically a default route that will redirect any unmatched URL’s.

The routing functionality is pretty straight forward but can have some side effects based on your choice of hash or browser history. Here we use hashHistory by declaring it as the history prop to our <Router/> component. The reason for using hashHistory here is for a more direct comparison to the part3 build and because it allows us to type route URL’s directly into the navigation bar. React Router has several different history types which you can learn more about here. Another reason to choose hashHistory over browserHistory is that browserHistory requires your server to handle URL changes by serving your default page. To me, pinging the server defeats the purpose of a single page routed application.

Now that we have our routes and our router declared it’s time to create the matching components. I’ve chosen to create as many stateless components as I can and will continue this style throughout this blog. I mention this because we will only use one stateful component but the common paradigm would be to have a stateful component as your top level ‘container’ component for each route and pass props down to its children.

So let’s start with our Home route. Here we will render our navigation and some text in a paragraph tag.

The Link components you see above are imported from React Router and generate links to our routes that look and behave just like an Html anchor tag. They take in a to prop which is the destination route and, like anchor tags, display the inner text. When clicked, they will both route your application to the appropriate sub page and update the URL in the navigation bar.

Next let’s create our input page shown above as the page1 route. This will be our stateful component as its children will be capturing user inputs.

There are a few new things happening here so let’s take a look at them. First notice that in our render we have a Link component which is imported from React Router just like before and allows us to route. These tags can be used anywhere in your code as long as you bring them in using an import.

Second let’s look at the this.props.history.push call at the bottom of the updateUser function. You’ll notice right away that we didn’t pass any props called history into the route component that renders Page1 so where did it come from? React Router gives you a few default props when it renders your view. One of them is history, and the other important one for us here is params or query. These two props pass values between our routes and allow us to transfer state from one route to the other. We’re not getting any params inputted into Page1 but notice the input to history.push: this represents the route we want to switch to, and at the end of route name we have our route params. This is the :user we declared earlier. Just like in an HTTP request the params is now available to the Page2 route as the props.params.user value. The history.push function adds the new route to the history object and by doing so switches our view and takes us to the new route.

Let’s take a look at the InputName child component that Page1 is rendering.

This component is fairly straight forward and doesn’t actually use any React Router methods so I’ll just quickly go over it. The most interesting thing happening here is the onSubmit, here we are capturing the React synthetic event and using it to prevent the form submit from refreshing the page with e.preventDefault. After we stop this from happening we call our passed down function that we called onclick passing in the synthetic event so that we can capture our required data up in the Page1 component.

The last component to discuss is our display page, the Page2 route.

Here in Page2 we are grabbing the params prop that we discussed above and using it to get the user submitted value from our Page1 form, and then simply displaying that value on the screen. The important thing to notice here is that the :user param that we gave to the route when we declared it is now available to the component as props.params.user.

And now with all the components written to fit the routes we declared we have a fully functional application. But there are still a few idiosyncrasies to note.

The first is the way the URL displays when using HashRouter. Remember the reason we choose hashRouter instead of the browserRouter is because we don’t have to make server calls every time we switch routes. But this gives us an ugly URL.

Notice all the extra stuff after the #/? This shows up on all your routes and changes every time you click a link. The benefit here is without any extra server setup you can type directly into the URL bar and route to a sub page.

The second thing to talk about here is the side effect of how we share state data in React Router. The use of params and query strings means that any data you share between routes is immediately visible in the URL. Notice in the picture below that when I enter the name John into our Page1 input the and route to Page2 the URL displays this data too. This can not only be unsightly but also exposes information that you might not want exposed.

Now that we understand these quirks and have built our simple app in React Router, lets try and overcome some of the quirks by bringing in Redux. In Part2 we will add Redux to this app and take a look at the overhead and quirks that arise.

--

--