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.
Instructor: [0:00] Now that we have multiple pages in our application, let's create a shared navigation bar so we can easily move between them. Let's create a new file called nav.js in a components folder, and let's build out our basic component. Let's display our nav component on every page by importing it in the _app.js file.
[0:22] We can display it above our component. We see that rendering on our pricing and home page. We want to render out a link for both of those pages. We'll put those inside a nav component. There we have our links, and we can navigate between those two pages. Let's make our nav bar look a little nicer, and maybe add a little margin between our two items.
[0:51] I want to display a Login button if that user is currently signed out, and a Logout button if they're currently signed in. I'm going to need to know about our user's state. We can destructure our user object from useUser.
[1:07] I want to render another link where the href prop depends on whether or not we have a user. If we have a user, we want to go to /logout. If we don't log in, we then want to have an A tag inside of that, again, where the text depends on whether or not we have a user. If we do, we want to say Logout. If we don't, we want to say Login.
[1:26] We probably want to push this link all the way over to the right. We can use ml-auto. That looks good. When I login, we'll see the text, Logout, and we can navigate between our two pages.
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>
)}
I'm running into this console warning:
Warning: Text content did not match. Server: "Login" Client: "Logout"
, everything is Seems to be caused by:In the nav component