#Hydration error caused by conditional rendering

24 messages · Page 1 of 1 (latest)

rigid hamlet
#
'use client';
import { useContext, useState } from 'react';
import FlashcardForm from './FlashcardForm';
import Login from './Login';
import useUser from '../libs/pocketbase';

export default function Home() {
    const { user } = useContext(useUser());
    return (
        <main className="grow grid place-items-center h-full">
            {user ? <FlashcardForm /> : <Login />}
        </main>
    );
}

This component causes an error, because the server renders the login page, but the client renders the flashcard form and the initial UI doesn't match what the server rendered during hydration. How would I go about fixing it?

spice fable
#

what does useUser return on Server/Client?

rigid hamlet
#

it returns a context

import PocketBase from 'pocketbase';
import { createContext, useState } from 'react';

export default function useUser() {
    const pb = new PocketBase('http://127.0.0.1:8090');
    const [user, setUser] = useState(pb.authStore.model);
    return createContext({ pb, user, setUser });
}
#

honestly I'm guessing my code is a mess, but I'm new to Next.js

spice fable
#

createContext should be used in a global scope, e.g.:

"use client";

const UserContext = createContext({});

export const useUser = () => {
    return useContext(UserContext);
};

export const UserProvider = ({children}) => {
    const pb = new PocketBase('http://127.0.0.1:8090');
    const [user, setUser] = useState(pb.authStore.model);

    return <UserContext.Provider value={{ pb, user, setUser }}>
        {children}
    </UserContext.Provider>;
};

Wrap the UserProvider around the children in your layout.

Then you can call useUser anywhere like this:

export default function Home() {
    const { user } = useUser();
    return (
        <main className="grow grid place-items-center h-full">
            {user ? <FlashcardForm /> : <Login />}
        </main>
    );
}
#

This might not solve the problem yet.

#

When you implement it like this, check if pb.authStore.model returns different values on client and server.

rigid hamlet
#

The error still shows up and pb.authStore.model returns the same values

rigid hamlet
#

@spice fable do you have any other ideas?

spice fable
#

If it returns the same value on both server and client, then the same component will be rendered, either FlashcardForm or Login

#

So the problem might be in there

rigid hamlet
#

Hm I might've checked for the value in a wrong way

#

How do I check what the server's value would be then?

spice fable
#

if you do a console.log or console.debug, the server-side output will be in the console window where you started the dev server

rigid hamlet
#

it prints null

#

😬

#
export function UserProvider({ children }: { children: React.ReactNode }) {
    const pb = new PocketBase('http://127.0.0.1:8090');
    const [user, setUser] = useState(pb.authStore.model);
    console.log(user);

    return <UserContext.Provider value={{ pb, user, setUser }}>{children}</UserContext.Provider>;
}
spice fable
#

What information does PocketBase need to work properly? I don't know this library. It seems to lack information that is available on the client, but not on the server.
I assume it's a cookie.

rigid hamlet
#

PocketBase is like Supabase or Firebase

#

and it's an SDK I'm using

spice fable
rigid hamlet
#

Idk if I'm proficient enough to do this

rigid hamlet
#

@spice fable I 'solved' the problem this way

'use client';
import FlashcardForm from './FlashcardForm';
import Login from './Login';
import { useUser } from './Pocketbase';
import { useEffect, useState } from 'react';

export default function Home() {
    const { pb, user, setUser } = useUser();
    const [show, setShow] = useState(false);
    useEffect(() => {
        if (show) setUser(pb.authStore.model);
        else setShow(true);
    }, [show]);
    return (
        <main className="grow grid place-items-center h-full">
            {show && (user ? <FlashcardForm /> : <Login />)}
        </main>
    );
}
#

I know useEffect doesn't run on the server, but it kinda works so I'll keep it this way until I find a better solution that isn't too hard to implement for me