Closed oviirup closed 2 years ago
Hi @GrayGalaxy, thanks for the issue!
I've tried to reproduce the bug adding an useLocalStorage
in the pages/index.tsx
in an empty Next app and the npm run dev
and npm run build
then npm run start
, but I haven't any warning message. How can I reproduce it?
I've seen your PR. I think this isn't a bug. The hook uses a window
API which is only available in the browser. Thus, if we try to call it in server-side, it prints a warning message to notice it to the dev, because it could create an unexpected behavior.
Your fix works to don't read localStorage
in an SSR environment, but it's a regression. The useLocalStorage
hook can be used in different parts of your application with the same key, and its value must be synchronized. In this case, if the value exists in the local storage, the hook should read it directly.
If you have another idea, it's welcome.
The warning occurs in next.js create_next_app
running on local server. I use it in component level on client side. Here is the code...
const Home: NextPage = (props) => {
const [value, setValue] = useLocalStorage<string>('value', 'Hello World')
return (
<div className="container">
Index Page
<p>{value}</p>
<button onClick={() => { setValue('newValue') }}>This is a Button</button>
</div>
)
}
And here is the full error...
Warning: Text content did not match. Server: "Hello World" Client: "newValue"
at p
at div
at Home (webpack-internal:///./pages/index.tsx:43:84)
at MyApp (webpack-internal:///./pages/_app.tsx:47:27)
at StyleRegistry (webpack-internal:///./node_modules/styled-jsx/dist/stylesheet-registry.js:231:34)
at ErrorBoundary (webpack-internal:///./node_modules/@next/react-dev-overlay/lib/internal/ErrorBoundary.js:26:47)
at ReactDevOverlay (webpack-internal:///./node_modules/@next/react-dev-overlay/lib/internal/ReactDevOverlay.js:90:23)
at Container (webpack-internal:///./node_modules/next/dist/client/index.js:331:9)
at AppContainer (webpack-internal:///./node_modules/next/dist/client/index.js:770:26)
at Root (webpack-internal:///./node_modules/next/dist/client/index.js:891:27)
See more info here: https://nextjs.org/docs/messages/react-hydration-error
Don't know why this happen, but it did not happened with create_react_app
, probably due to caching. But using the initialValue
instead of readValue()
solved it.
Hm, weird. I've re-test your component, and I haven't any warning messages.
This is my package.json
:
{
"name": "next-app",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"next": "12.0.8",
"react": "17.0.2",
"react-dom": "17.0.2",
"usehooks-ts": "^2.2.1"
},
"devDependencies": {
"@types/node": "17.0.10",
"@types/react": "17.0.38",
"eslint": "8.7.0",
"eslint-config-next": "12.0.8",
"typescript": "4.5.5"
}
}
I need more to help you, what else are you using, which versions? Would you create a bug reproduction?
Don't know what happened, I clan installed the dependencies now it's working fine.
Weird, but cool if you're ok now (:
Maybe was the 2.2.1 release where i've updated how the lib was built (cjs/esm fix)
I'm having problems in Next.js too and would appreciate any tips if you have a moment: https://stackoverflow.com/questions/74022328/how-to-solve-react-hydration-error-in-next-js-when-using-uselocalstorage-and
@juliencrn I ran into this issue just now. Was able to resolve it by copying the useLocalStorage hook exactly, and only altering this line:
to read
const [storedValue, setStoredValue] = useState<T>(initialValue)
instead.
Presumably Next just wants the initial value to be the same on both client and server.
435 should fixes this
@juliencrn, I'm not sure moving the evaluation of serverside-ness to outside the function like that PR is doing is going to work. This issue is caused by the initial state value being different on server than it is on client, simply changing where in the code that gets evaluated isn't going to change anything.
On Server:
Initial state loaded with initialValue
, a hardcoded value. UI is created based on that value.
On Client:
Initial state loaded with whatever's in local storage. If this hook has been used before, that's very likely not initialValue
.
The reason my adjustment fixed the issue is because both client and server are loaded with the value of initialValue
. Loading of the local storage value needs to happen after the initial state load, not during it.
Next JS prebuilds pages, so when using the
useLocalStorage
hook it creates a warning link