react-hook
react-hook copied to clipboard
[useMediaQuery] React hydration doesn't re-evaluate the hook
Describe the bug
Next.JS does SSR and this hook sends a false
first and then React doesn't update when it client-side detects a true
. I made a work-around that makes it work. I am not sure what what internals make this problem occur.
To Reproduce
const isDesktop = useMediaQuery("(min-width:900px)");
I return different HTML depending on whether isDesktop
is true or false and it seems like React assumes that that the HTML it got from the server was with isDesktop = true
while it was when isDesktop = false
. For things like this I have always made a useEffect
to change the value and not useState(theCurrentValue)
which would cause a discrepancy between server and browser.
Expected behavior Correctly rendered HTML.
Here is my work-around that makes this work regardless:
const isDesktop_ = useMediaQuery("(min-width:900px)");
const [isDesktop, setIsDesktop] = useState(false);
// Work-around for server-side render
useEffect(() => {
setIsDesktop(isDesktop_);
}, [isDesktop_]);
This is always going to be a problem with SSR hydration. I am hesitant to add any logic to the hook to support this, because it encourages the anti-pattern of using JavaScript to change layout instead of CSS in situations where things are clearly being rendered outside of the window
while simultaneously making the hook force a new render each client-side render. Probably not the answer you're looking for, but I don't see this changing. Happy to be convinced by others.
I had the same issue with useWindowSize
.
My workaround:
useSsrCompatible.tsx
:
import { useState, useEffect } from "react";
export function useSsrCompatible<T>(newValue: T, initialValue: T) {
const [value, setValue] = useState(initialValue);
useEffect(() => {
setValue(newValue);
}, [newValue]);
return value;
}
Then use it like this:
- const [ width, height ] = useWindowSize();
+ const [ width, height ] = useSsrCompatible(useWindowSize(), [0,0]);
which makes Next.js' SSR happy.
Definitely not ideal and makes sense not to include in the library. Although others may find this useful when needing to accomplish this, so glad there is an issue to track the question.
That's very good! I like it a lot.