Next.js 中的布局持久性

2025-06-10

Next.js 中的布局持久性

虽然“布局”这个词通常与 CSS 页面布局相关,但我发布这篇文章的原因却略有不同。将导航栏的位置固定在顶部并不意味着当用户定向到另一个页面时导航栏不会被卸载。对于SPA(单页应用程序),导航栏在整个路由过程中保持挂载状态是预期的行为。虽然在CRA (Create React App)上很容易实现这一点,但在GatsbyNext.js中维护布局持久性可能很困难,因为代码拆分导致路由有所不同。在本文中,我们将在不使用Next.js 中的任何库的情况下,确保页面转换期间布局组件的持久性。

首先,如果尚未添加,我们需要在”/pages”目录下添加一个“_app.js”文件。这样,我们就可以介入应用程序的初始化过程,并能够在即将创建的布局组件中包含页面组件。最简单的“_app.js”文件如下所示:

export default function MyApp({ Component, pageProps }) {
  return <Component {...pageProps} />
}
Enter fullscreen mode Exit fullscreen mode

在这里我们将为应用添加布局支持。让我们将“/pages”下创建的“_app.js”文件修改如下:

import React from "react";

export default function MyApp({ Component, pageProps }) {
  const Layout = Component.Layout ? Component.Layout : React.Fragment;

  return (
    <Layout>
      <Component {...pageProps} />
    </Layout>
  )
}
Enter fullscreen mode Exit fullscreen mode

这里的组件是指返回当前 URL 路径的组件。例如,如果您在首页,则默认从“/pages/index.js”导出的组件将返回此处。因此,我们将把之前创建的布局组件直接添加到页面组件中。稍后再讨论这个问题。现在,我们来创建布局。为了保持项目整洁,我们可以将其创建在“/layouts/MyLayout.js”下:

import React, { useState } from "react";

export default function MyLayout({ children }) {
  const [counter, setCounter] = useState(0);

  return (
    <>
      <p>      
        <button onClick={() => setCounter(counter + 1)}>
          Clicked {counter} Times
        </button>
      </p>

      {children}
    </>
  )
}
Enter fullscreen mode Exit fullscreen mode

如果我们能够通过“pages/_app.js”中的魔法实现布局持久化,那么带有计数器的按钮显示的数字在路由过程中就不会被重置。因此,让我们在“pages”文件夹下创建两个示例页面来测试一下。首先是“/pages/profile.js”

import Link from "next/link";

export default function Profile() {
  return (
    <div>
      <p>This is the Profile page.</p>
      <p>
        <Link href="/account">
          <a>Go: Account</a>
        </Link>
      </p>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

那么,我们如何将刚刚创建的布局组件添加到这个页面组件中呢?正如我之前提到的,直接……

import Link from "next/link";
import MyLayout from "../layouts/MyLayout";

export default function Profile() {
  return (
    <div>
      <p>This is the Profile page.</p>
      <p>
        <Link href="/account">
          <a>Go: Account</a>
        </Link>
      </p>
    </div>
  );
}

Profile.Layout = MyLayout;
Enter fullscreen mode Exit fullscreen mode

嗯,这并不复杂。让我们继续在“/pages/account.js”下添加第二个示例页面:

import MyLayout from "../layouts/MyLayout";

export default function Account() {
  return (
    <div>
      <p>This is the Account page.</p>
      <p>
        <Link href="/profile">
          <a>Go: Profile</a>
        </Link>
      </p>
    </div>
  );
}

Account.Layout = MyLayout;
Enter fullscreen mode Exit fullscreen mode

一切准备工作都已完成。现在我将在浏览器中为您打开“个人资料”页面。我将点击带有计数器的按钮4 次。然后我将转到“帐户”页面,结果将是:

替代文本

由于这两个页面共享相同的布局组件,因此计数器在路由过程中没有重置。如果我转到其他页面,MyLayout将被卸载,计数器也会重置。

这样,你就能让标签栏等导航元素跨页面保持一致。或者,你也可以去厨房烤个草莓蛋糕,我也不知道,就此结束。


我希望这篇文章对您有所帮助,您也可以在 Twitter 上关注我以获取未来的内容:

twitter.com/ozanbll

鏂囩珷鏉ユ簮锛�https://dev.to/ozanbolel/layout-persistence-in-next-js-107g
PREV
现代前端 Web 开发路线图
NEXT
GRPC 节点 + NextJs + Prisma + Envoy 代理