I'm facing React's hydration error, which - according to the documentation - is caused by "using browser-only APIs like window or localStorage in your rendering logic".
This probably happening at all places where I'm checking whether the user is logged in (and often run GraphQL queries for user-specific elements to display on the client-side), b/c I'm using cookies here (simplified):
import { useCookies } from 'react-cookie';
export const useSessionCookieData = (): Session => {
const [cookieData] = useCookies(sessionKey);
return cookieData.session.accessToken;
};
My core idea was that the page is rendered on the server side as if being logged out, and the client-side might change this in case the user is logged in. My question is which solution is preferable or whether there's even a better one than those:
export const useSessionCookieData = (): Session => {
const [cookieData] = useCookies(sessionKey);
return cookieData.session.accessToken;
};
Since useCookies
calls useState
internally (and additionally ensures whether it's in browser, but by "forbidden" window
checks), I'ld expected it to automatically enforce client-side rendering, but - as the hydration error conveys - that doesn'twork. Is there any way I could make sure using useSessionCookieData
enforces the calling component to client-side one only? Adding something like
const [mounted, setMounted] = useState(false);
useEffect(() => setMounted(true), []);
if (mounted) return undefined;
in my useSessionCookieData
doesn't change anything, either, and additionally I don't want to return undefined
initially (and trigger an undesired redirect to the login page in some circumstances).
3.) I could try to pass the access token to the server-side and let it do all the queries. This is probably rather hard and means quite a rewrite?
At the moment, I have the impression that my use case - a rather customized website - is not made for server-side rendering, and there probably isn't much gain from it. So I'm in favor of option 1.)
Are there any other ideas or recommendations how to deal with that problem?
Personally, I have a terrible experience with react-cookie
that makes it work the React way -- for example, you can add dependency in the argument so when the cookie changes, it should rerender the component, but NOPE, it doesn't work that way.
Anyway, there are a couple of problems I can observe --
context
.export const getServerSideProps: GetServerSideProps = async (context) => {
const cookie = context.req.cookies
// ...
}
whereas in CSR, you get cookie from window
object like window.document.cookie
or just document.cookie
.
So its probably one of the reason why your page didn't get hydrated properly -- the cookie is not properly parsed and validated.
universal-cookie
instead to get/set cookies the traditional way. It is included in the react-cookie
so you don't have to install another module.import { Cookies } from 'react-cookie'
const cookies = new Cookies()
// get a key of a cookie
const someCookieValue = cookies.get('some-cookie-key')
// set a key to a cookie
cookies.set('some-cookie-key', 'some-value')