Manually typing the URL to navigate between our different pages is becoming cumbersome. Let's create a shared navigation bar that will display on every page in our application.
In this video, we create a new component to display our Nav
options - /
and /pricing
. Each of our routes uses the Next.js <Link>
component to make transitions between pages client-side. By rendering our <Nav>
component in pages/_app.js
, our navbar will display on every page.
Additionally, we would like to dynamically swap out our login
and logout
options, based on the user's signed in status. In order to do this, we can use the useUser
hook and conditionally render each link based on our user's state.
I'm running into this console warning:
Warning: Text content did not match. Server: "Login" Client: "Logout"
, everything is Seems to be caused by:
<Link href={user ? '/logout' : '/login'}>
<a className="ml-auto">{user ? 'Logout' : 'Login'}</a>
</Link>
In the nav component
When i login and refresh the start-page i get an hydration error: "Error: Hydration failed because the initial UI does not match what was rendered on the server."
@James in user.js initializing our user state with "userState(null)" instead of "userState(superbase.auth.user()) fixes the problem.
After an intense read about hydrating, i think it's because while rendering the page on the server, it cant resolve superbase.auth.user() (because it retrieves the user object from localstorage(?) and the server has no access to localstorage) but on the clients first render, there is a user object, which results in content not matching between server and client.
I hope you get the point
That is exactly the problem! I am working on a revision for the course that fixes this issue, but until then, here is a blog that demonstrates how to switch off SSR for the Navbar component
https://jonmeyers.io/blog/fix-client-server-hydration-error-in-next-js
I fixed the hydration error by doing this:
import Link from 'next/link';
import { useUser } from '../context/user';
const Nav = () => {
const { user, isLoading } = useUser();
return (
<nav>
<Link href="/">
<a>Home</a>
</Link>
<Link href="/pricing">
<a>Pricing</a>
</Link>
{!isLoading && (
<Link href={user ? '/logout' : '/login'}>
<a>{user ? 'Logout' : 'Login'}</a>
</Link>
)}
</nav>
);
};
export default Nav;
If you're wondering where this isLoading
is coming from, this is something that is covered in lesson 18 - "Query Dynamic Supabase Data in Static Pages Using Next.js".
isLoading
is set to true
when UserProvider
is loading.
If it's loading then we prevent the login
or logout
link to show with:
{!isLoading && (
<Link href={user ? '/logout' : '/login'}>
<a>{user ? 'Logout' : 'Login'}</a>
</Link>
)}