1. 17
    Create Shared Nav Bar in Next.js with _app.js
    1m 39s

Create Shared Nav Bar in Next.js with _app.js

Jon Meyers
InstructorJon Meyers

Share this video with your friends

Send Tweet
Published a year ago
Updated 11 months ago

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.

James
James
~ 7 months ago

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

Martin
Martin
~ 5 months ago

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."

Martin
Martin
~ 5 months ago

@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

Jon Meyers
Jon Meyersinstructor
~ 4 months ago

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

Melwyn Turbant
Melwyn Turbant
~ 2 months ago

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>
      )}