'What's hydrate action in Next Redux Wrapper?
Recently I started using Next.js and I have a question about the next-redux-wrapper package. I don't really understand the HYDRATE
action. So I wonder concretely what it is, what is it for and when is it launched.
Because currently the only thing I really understood is that it is used with the getServerSideProps
function to allow the store to be "loaded" before rendering the page.
But that leaves a lot of questions unanswered, for example :
export const getServerSideProps = wrapper.getServerSideProps(store => () => {
store.dispatch(getTasks())
})
In this case I wonder what is the point of dispatching the getTasks
action since it will be the HYDRATE
action that will be played. Or why use the next-redux-wrapper package instead of just using a normal getServerSideProps
function in which we would dispatch the getTasks
action by simply importing the store?
This may seem silly but since there are few resources on this and I'm quite inexperienced, added to that I'm French. So I'm having trouble understanding the usefulness of a wrapper.
I would so be grateful to provide me with clear answers, taking into account my difficulties.
Solution 1:[1]
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 getCannot 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.
Solution 2:[2]
Whenever next.js gets a new request, it newly builds the page on the server side and send it back to the client browser. the problem is server is not aware of the client side redux store. So, what it does is, it creates new store, updates with new values. Somehow we need to update these new store values which is present in the server side to the values that are present on the client side store. Otherwise, fetched data stored in the store will be lost.
so we modify our reducer a little bit so that we can handle such request and we are able to persist both the server-side redux store and the client side redux store values so that we have a universal store.
const mainReducer = (state, action) => {
// hydration is a process of filling an object with some data
// this is called when server side request happens
if (action.type === HYDRATE) {
const nextState = {
...state,
...action.payload,
};
return nextState;
} else {
// whenever we deal with static rendering or client side rendering, this will be the case
// reducers is the combinedReducers
return reducers(state, action);
}
};
HYDRATE
action dispatched whenever there is a server side call and we need to look out for this action in our main reducer where we will be handling the Hydrate
action. with this, we are appying the new store values to the client store. hydration is a process of filling an object with some data. So we are filling the client side store with the server-side store data
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 |