ReactJS : Server side rendering with router v4 & redux
Revath S Kumar
When I wrote React.js: Server side rendering a few months back, I used react router v3.0.2. But ever since react router released v4, which is a total rewrite into a declarative format, the old blog post won't work with react router v4. So I decided to write a new blog as 2nd part of it which uses react router v4 along with redux.
Since we already have a blog post explaining the initial setup, I will be skipping the repeated steps needed here but will add the new updates need to use the new router.
Major Router Updates
Major changes in React Router v4 are
Declarative routing
No more central routes config
Separate packages for web & native
No onEnter or onChange hooks/callbacks, instead use component lifecycle hooks
Adding React Router v4 to our application
Since react router has separate packages for web and native, let go with installing the package needed for the web.
react-router-config package will have configuration helpers to use with StaticRouter for server side rendering.
If your application already has react-router package, I recommend you to remove it and use only the above ones.
Adding Redux to our application
Let add the redux packages need for our application. Since this demo contains async actions we will add redux-thunk package as well.
If you are not familiar with the redux setup you can follow my previous blog on Getting started with redux.
Also, let's install isomorphic-fetch so we can use fetch on both server and client.
Setup React Router
Setting up the Router will start with defining the routes.
And load the routes on client side like
Here <BrowserRouter> is a new component provided by react router which uses HTML5 history API. The above setup is used only on client side.
For server side rendering we will be using <StaticRouter> component.
Render static component on Server
As same as PART 1, we have a /home route which will render some HTML. No dynamic content or data from API.
Even though our Home component is same, we have a different setup on routes/index.jsx.
Render component with data
Now when it comes to rendering component with data, we need to make some changes to the express route, setup redux store and
add static method on a component to fetch the data and update the store.
Since we are using redux we need to setup reducer & action to fetch the user details from API. Here I will be using erikras/ducks-modular-redux pattern, so the constants, reducer & actions will be available in a single file.
Now let's modify the List component to use the fetchUsers action and also add a fetchData static method which can be used on the server.
Now the updates for the express route.
In the above snippet, matchRoutes will filter the routes and components needed to render the given URL.
Once we have the list of routes for the given URL, we can map through each and check whether it has a static method named
fetchData. If the component has the fetchData method, then execute those else return a null promise.
Once we collect all the promises, executed and updated the store, we can render the component using <StaticRouter> component and return the data and compiled HTML to the client.
Now when we navigate to /list, the route we can see the list of users rendered from the server.
Handling 404
Next, let's see how to handle the 404. In this case just rendering the NotFound component is not enough, we have to return back appropriate status code to the client as well.
Let's start with adding NotFound component
In NotFound component, rendering some 404 message is not enough. We should be setting the status on staticContext so that when rendering on the server we can access the status on the context object we passed.
Remember staticContext will be available only on the server, so make sure we guard the setting of status with if condition.
next, we add the route to handle 404.
Now we need to update the express routes to set the response status as 404.
Handling Redirects
After handling 404, now we can handle redirects in a similar way. For redirects, we will be using <Redirect> component from react router. To show the redirection we will be redirecting /list route to a new route /users where we will list the users from API.
For this, we will define a new component ListToUsers which utilises <Redirect>.
As we did in handling 404, here as well we need to set the status on staticContext to 302 or 301 as per your need. Here I am using 302.
Now let's update the routes.
Next, make necessary changes for express routes so it will perform redirect
Now we have a fully functional server rendered react application.
The demo app is available on github and working demo can be found in now.sh