You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NextJS中如何为404页面创建独立自定义布局?

解决Next.js 404页面继承根布局Footer的问题

问题原因

在Next.js App Router中,not-found.tsx会被自动嵌套在根layout.tsx内部执行,所以根布局里的Footer等组件会始终渲染,哪怕你给404页面套了自定义布局。同时你当前的JFCNotFound组件重复渲染了<html>和<body>标签,会导致DOM嵌套错误,这也是需要修正的点。


方案一:在根布局中跳过404页面的Footer渲染

这种方法通过上下文标记404页面状态,让根布局根据状态决定是否渲染Footer:

  1. 创建NotFound上下文文件
// app/NotFoundContext.tsx
'use client';
import { createContext, useContext, ReactNode } from 'react';

const NotFoundContext = createContext<boolean>(false);

export function NotFoundProvider({ children, isNotFound }: { children: ReactNode; isNotFound: boolean }) {
  return (
    <NotFoundContext.Provider value={isNotFound}>
      {children}
    </NotFoundContext.Provider>
  );
}

export function useIsNotFound() {
  return useContext(NotFoundContext);
}
  1. 修改not-found.tsx,添加上下文包裹
// app/not-found.tsx
import Link from 'next/link';
import JFCNotFoundLayout from '@/components/JFCLayouts/JFCNotFound';
import { NotFoundProvider } from './NotFoundContext';

export default function NotFound() {
  return (
    <NotFoundProvider isNotFound={true}>
      <JFCNotFoundLayout>
        <div className='text-center'>
          <h2 className='text-3xl'>There was a problem.</h2>
          <p>We could not find the page you were looking for.</p>
          <p>Go back to the <Link href="/">dashboard</Link></p>
        </div>
      </JFCNotFoundLayout>
    </NotFoundProvider>
  );
}
  1. 修正根layout.tsx,根据状态控制Footer渲染
// app/layout.tsx
'use client';
import type { Metadata } from 'next';
import Head from 'next/head';
import '../styles/globals.css';

import { Footer } from '../components/Footer';
import JFCProvider from '../redux/JFCProvider';
import { useIsNotFound } from './NotFoundContext';

export const metadata: Metadata = {
  title: 'My App',
  description: 'My App'
};

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  const isNotFound = useIsNotFound();

  return (
    <html lang="en">
      <Head>
        <meta http-equiv="ScreenOrientation" content="autoRotate:disabled" />
      </Head>
      <body suppressHydrationWarning={true}>
        <JFCProvider>
          {children}
          {!isNotFound && <Footer />}
        </JFCProvider>
      </body>
    </html>
  );
}
  1. 修正JFCNotFound组件,移除重复的<html>和<body>标签
// components/JFCLayouts/JFCNotFound.tsx
'use client';
import React from 'react';
import '../../styles/globals.css';
import './style.css';

const JFCNotFound = ({
  children,
}: {
  children: React.ReactNode;
}) => {
  return (
    <div className="jfc not-found">
      {children}
    </div>
  );
};
export default JFCNotFound;

方案二:使用分组布局分离页面(推荐)

这种方法符合App Router的设计逻辑,将需要Footer的页面放在分组目录中,404页面独立在根目录,避免继承多余布局:

  1. 创建分组目录app/(main),将所有正常页面(如page.tsx、dashboard/page.tsx等)移入该目录
  2. 在app/(main)下创建专属布局,放置Footer等组件
// app/(main)/layout.tsx
import { Footer } from '../../components/Footer';

export default function MainLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <>
      {children}
      <Footer />
    </>
  );
}
  1. 简化根layout.tsx,只保留全局基础包裹
// app/layout.tsx
import type { Metadata } from 'next';
import Head from 'next/head';
import '../styles/globals.css';

import JFCProvider from '../redux/JFCProvider';

export const metadata: Metadata = {
  title: 'My App',
  description: 'My App'
};

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <Head>
        <meta http-equiv="ScreenOrientation" content="autoRotate:disabled" />
      </Head>
      <body suppressHydrationWarning={true}>
        <JFCProvider>
          {children}
        </JFCProvider>
      </body>
    </html>
  );
}
  1. 修正JFCNotFound组件(同方案一的步骤4)

此时not-found.tsx位于根目录,只会继承根布局,不会加载(main)分组里的Footer组件。

内容的提问来源于stack exchange,提问作者rochellecanale

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 04:20:59