I'm getting Error:
Rendered more hooks than during the previous render.
I found some answers saying I should put all hook calls on the top.
However, in the following code, session
prints undefined
3 times while it's loading until it prints the session
object the fourth time.
Hence, I added a check for the loading
state.
import { signIn, signOut, useSession } from "next-auth/client";
import { request } from "graphql-request";
import useSWR from "swr";
export default function Profile() {
const [session, loading] = useSession();
if (loading) {
return <p className="">loading...</p>;
}
if (!session) {
signIn();
}
const { data: user } = useSWR([USER_QUERY, session.email], (query, email) =>
request("/api/graphql", query, { email })
);
return (
<div className="">
<p className="">{session.user.nickname}</p>
<button onClick={() => signOut()}>Sign out</button>
</div>
);
}
However, this is throwing an error.
A workaround for this particular issue is to define a NextAuth
callback for session
, but I don't think that's the correct way to fix it, since I definitely will need to make other hook calls based on the value in the session
object in the future.
How can I fix this?
Because hooks are tracked by array index internally by React, you can't invoke them conditionally. You need the same hook calls in the same order each time a given component renders.
You could move the useSWR
and subsequent markup to a separate component to avoid the conditional hook calls.
In the example below I've moved the signIn call to a separate component too, but that's not strictly necessary. If you wanted to leave that inline you could just return null instead.
export default function Profile() {
const [session, loading] = useSession();
if (loading) {
return <p className="">loading...</p>;
}
return !session ? <SignIn /> : <UserStuff />
}
function SignIn () {
signIn();
return null;
}
function UserStuff () {
const { data: user } = useSWR([USER_QUERY, session.email], (query, email) =>
request("/api/graphql", query, { email })
);
return (
<div className="">
<p className="">{session.user.nickname}</p>
<button onClick={() => signOut()}>Sign out</button>
</div>
);
}