Some projects require you to render your application on the server. There are different reasons to do this, like search engine optimizations, general optimizations and even browser support. What this means for state management is that you want to expose a version of your state on the server and render the components with that state. But that is not all, you also want to hydrate the changed state and pass it to the client with the HTML so that it can rehydrate and make sure that when the client renders initially, it renders the same UI.
Preparing the project
When doing server-side rendering the configuration of your application will be shared by the client and the server. That means you need to structure your app to make that possible. There is really not much you need to do.
Here we only export the configuration from the main Overmind file. The instantiation rather happens where we prepare the application on the client side. That means we can now safely import the configuration also on the server.
Preparing effects
The effects will also be shared with the server. Typically this is not an issue, but you should be careful about creating effects that run logic when they are defined. You might also consider lazy-loading effects so that you avoid loading them on the server at all. You can read more about them in EFFECTS.
Rendering on the server
When you render your application on the server you will have to create an instance of Overmind designed for running on the server. On this instance you can change the state and provide it to your components for rendering. When the components have rendered you can hydrate the changes and pass them along to the client so that you can rehydrate.
Overmind does not hydrate the state, but the mutations you performed. That means it minimizes the payload passed over the wire.
The following shows a very simple example using an EXPRESS middleware to return a server side rendered version of your app.
On the client you just want to make sure that your Overmind instance rehydrates the mutations performed on the server so that when the client renders, it does so with the same state. The onInitialize hook of Overmind is the perfect spot to do this.
If you are using state first routing, make sure you prevent the router from firing off the initial route, as this is not needed.
OnInitialize
The onInitialize action does not run on the server. The reason is that it is considered a side effect you might not want to run, so we do not force it. If you do want to run an action as Overmind fires up both on the client and the server you can rather create a custom action for it.
The idea behind setting up overmind in next.js is the same as a standard express server but we have a lot of help from next to get us going.
Let's start by adding a _document.js and this is where we will initialize the SSR version of Overmind:
import App from"next/app";import { createOvermind, createOvermindSSR, rehydrate } from"overmind";import { Provider } from"overmind-react";import { config } from"../overmind";exportdefaultclassMyAppextendsApp {// CLIENT: On initial route// SERVER: On initial routeconstructor(props) {super(props);constmutations=props.pageProps.mutations || [];if (typeof window !=="undefined") {// On the client we just instantiate the Overmind instance and run// the "changePage" actionthis.overmind =createOvermind(config);this.overmind.actions.changePage(mutations); } else {// On the server we rehydrate the mutations to an SSR instance of Overmind,// as we do not want to run any additional logic herethis.overmind =createOvermindSSR(config);rehydrate(this.overmind.state, mutations); } }// CLIENT: After initial route, on page change// SERVER: nevercomponentDidUpdate() {// This runs whenever the client routes to a new pagethis.overmind.actions.changePage(this.props.pageProps.mutations || []); }render() {const { Component,pageProps } =this.props;return ( <Providervalue={this.overmind}> <Component {...pageProps} /> </Provider> ); }}
And then let's create a standard Overmind instance: