You need to realize why you need it from the start on your Next.js server with Redux.
There are actually two different instances of your store
There are two scenarios in React-wise on Next.js: SSR and CSR. Remember that Next.js can't send clients any javascript objects more complicated than serializable JSON, which means the instance of your store that clients have is not the instance that you initialize and put in your React app on server side.
For example, there will be two different StoreInstance
, one is on server side and the other one is on client side.
// pages/_app.js
import StoreInstance from ...
export default function App({ Component }) {
return (
<Provider store={StoreInstance}>
<Component />
</Provider>
);
}
So if you initialize some states of StoreInstance
inside a server side only lifecycle like getServerSideProps
, you are only doing it to the server side instance, thus the client side instance won't have the same state at initial page loads.
For further information, this results in difference between markup that Next.js made and markup that React.js made which is derived from Next.js' hydration at initial page load. (And Next.js detects this differences and emits this warning: Warning: Did not expect server HTML to contain the text node
)
Each generated HTML is associated with minimal JavaScript code necessary for that page. When a page is loaded by the browser, its JavaScript code runs and makes the page fully interactive. (This process is called hydration
)
Your codes will run on both SSR and CSR on Next.js
What if you initialize some states of StoreInstance
inside a lifecycle like _app
which runs on both server side and client side? Well, when you navigate the same page through Link
(which derives CSR), you'll meet warning Warning: Cannot update a component ('Page') while rendering a different component ('App')
, which seems to be caused by race conditions as next-redux-wrapper
auther notes:
It is highly recommended to use pages/_app
to wrap all pages at once, otherwise due to potential race conditions you may get Cannot update component while rendering another component
What is the HYDRATE
action
Now you see that you need to have the two store intances having same states(at initial loads) while respecting the race conditions. And next-redux-wrapper
accomplishes this by hydrating
the states of the server side instance into the client side instance(this hydration is the same concept as the one in Next.js). And because it implemented the hydration
in the same way that Redux works, it had to make the action's type HYDRATE
so you can distinguish it from Redux's usual updates.
Why did the module auther choose this way to make it work? He said it's because if you just replace the store on CSR, Redux will re-render everything even when it's not necessary.
In Next.js example https://github.com/vercel/next.js/blob/canary/examples/with-redux/store.js#L55 store is being replaced on navigation. Redux will re-render components even with memoized selectors (createSelector from recompose) if store is replaced: https://codesandbox.io/s/redux-store-change-kzs8q, which may affect performance of the app by causing a huge re-render of everything, even what did not change. This library makes sure store remains the same.
When is HYDRATE
action dispatched
The action gets dispatched with the initial state of your store whenever your _app
gets requests, whether or not you dispatch something to your store on server side.