You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Usage of cartCount causes an SSR mismatch error in Next.js #122
I did some digging and traced it down to the react-storage-hooks module: soyguijarro/react-storage-hooks#17 . Maybe they have seen that before and have an idea.
So @thorsten-stripe the official way to fix it would be to modify react-storage-hooks to not load from LocalStorage on the initial client-side render, but instead right afterward right?
So @thorsten-stripe the official way to fix it would be to modify react-storage-hooks to not load from LocalStorage on the initial client-side render, but instead right afterward right?
@ChrisBrownie55 Yes, I believe that is the only way to avoid this discrepancy, however it's not great, because you have an initial render with the default state and then an immediate re-render with the localStorage state, which can result in a flicker when the page loads.
One potential solution would be to initially return null until we had the chance to check the localStorage, that way you can employ conditional rendering to avoid the "flicker", but none of this feels great for non-SSR applications :(
So what I'm seeing here is that we need to display the default (a.k.a. empty) values for data stored in local storage and provide a status indicator for the data as well.
I think this could look something like the following:
exportfunctionuseLocalStorageReducer(key,reducer,initialState){const[state,dispatch]=useReducer((state,action)=>{switch(action.type){case'value updated':
return{status: 'loaded',value: action.storageValue}case'loading started':
return{status: 'loading',value: action.initialState}default:
returnstate}})constdummyStorage={/* ... */}conststorageValue=useStorageReducer(/* same stuff but make initial state: */null)useEffect(()=>{if(storageValue===null)dispatch({type: 'loading started', initialState })elsedispatch({type: 'value updated', storageValue })},[initialState,storageValue])}
This would also make it so that when isClient is false it will always be status: 'loading'. Although, I don't think this accounts for window.localStorage being inaccessible, like if it's disabled, as we currently aren't handling that anyway.
It looks like setting suppressHydrationWarning is the only option until soyguijarro/react-storage-hooks#20 is merged. Once it is, we'll need to update our dependency. For now, I'll just tag this as "On Hold".
which not only triggers the hydration warning, but also a mismatched className on the Badge being invisible (server side) or not (client side).
My only solution, for now, has been to go with the premise that the shopping cart interaction will be client-side only, and wrap any use of cartCount in <NoSSR>
I'd say that that's a fair assumption as all of the cart information has to be loaded from either LocalStorage or with loadCart. However, @benwwalker, I feel like the hydration warning is triggered in your above example because you're still conditionally rendering different values to the DOM based on cartCount. You might try something like:
// "hidden" would be like "display: none" or something<IconButtonhref="/cart"className={cartCount>0 ? '' : 'hidden'}suppressHydrationWarning><BadgebadgeContent={cartCount||0}color="secondary"><ShoppingCartOutlined/></Badge></IconButton>
If you still have the same issue with suppressHydrationWarning then <NoSSR> might be the only way at the time.
Activity
thorsten-stripe commentedon Jun 12, 2020
This sounds similar: https://dev.to/jaklaudiusz/next-js-persistent-state-with-react-hooks-and-localstorage-how-to-make-it-work-3al6 but not sure how we can bake that into the lib.
thorsten-stripe commentedon Jun 13, 2020
I did some digging and traced it down to the
react-storage-hooksmodule: soyguijarro/react-storage-hooks#17 . Maybe they have seen that before and have an idea.thorsten-stripe commentedon Jun 13, 2020
There is a workaround: https://github.com/thorsten-stripe/next.js/commit/64ce389ed776e935584d35f9859a50f0f6b2c745
However the usage of
suppressHydrationWarningis discouraged: https://reactjs.org/docs/dom-elements.html#suppresshydrationwarningandria-dev commentedon Jun 14, 2020
So @thorsten-stripe the official way to fix it would be to modify
react-storage-hooksto not load from LocalStorage on the initial client-side render, but instead right afterward right?andria-dev commentedon Jun 14, 2020
Oh nvm looks like you're really on top of all this and you've already put out a PR for this. Much appreciated.
thorsten-stripe commentedon Jun 15, 2020
@ChrisBrownie55 Yes, I believe that is the only way to avoid this discrepancy, however it's not great, because you have an initial render with the default state and then an immediate re-render with the localStorage state, which can result in a flicker when the page loads.
One potential solution would be to initially return null until we had the chance to check the localStorage, that way you can employ conditional rendering to avoid the "flicker", but none of this feels great for non-SSR applications :(
dayhaysoos commentedon Jun 22, 2020
@thorsten-stripe it looks like this has been fixed here:
soyguijarro/react-storage-hooks#8
You think you can try testing the upgraded version of
react-storage-hooksand see if the bug is gone?thorsten-stripe commentedon Jun 24, 2020
Unfortunately it didn't fix the hydration warning issue, see soyguijarro/react-storage-hooks#18 (comment)
andria-dev commentedon Jun 24, 2020
So what I'm seeing here is that we need to display the default (a.k.a. empty) values for data stored in local storage and provide a status indicator for the data as well.
I think this could look something like the following:
This would also make it so that when
isClientis false it will always bestatus: 'loading'. Although, I don't think this accounts forwindow.localStoragebeing inaccessible, like if it's disabled, as we currently aren't handling that anyway.dayhaysoos commentedon Sep 23, 2020
@thorsten-stripe was this taken care of? Do we need to update this lib?
[-][Next.js] CartCount throws error on reload[/-][+]Usage of cartCount causes an SSR mismatch error in Next.js[/+]andria-dev commentedon Feb 16, 2021
It looks like setting
suppressHydrationWarningis the only option until soyguijarro/react-storage-hooks#20 is merged. Once it is, we'll need to update our dependency. For now, I'll just tag this as "On Hold".benwwalker commentedon Feb 19, 2021
Fwiw I've been running into this whilst using material-ui badges too - things like
which not only triggers the hydration warning, but also a mismatched className on the Badge being invisible (server side) or not (client side).
My only solution, for now, has been to go with the premise that the shopping cart interaction will be client-side only, and wrap any use of cartCount in
<NoSSR>andria-dev commentedon Feb 19, 2021
I'd say that that's a fair assumption as all of the cart information has to be loaded from either LocalStorage or with
loadCart. However, @benwwalker, I feel like the hydration warning is triggered in your above example because you're still conditionally rendering different values to the DOM based oncartCount. You might try something like:If you still have the same issue with
suppressHydrationWarningthen<NoSSR>might be the only way at the time.Other than that, we're still just waiting on soyguijarro/react-storage-hooks#20 to be merged to definitively solve this issue.
dayhaysoos commentedon Jul 4, 2021
Don't think this is an issue anymore, let me know if I'm wrong tho