nextjs系列教程(六):自定义App、Document、404页面、服务器跨域

文章介绍了如何在Next.js中自定义App组件以实现页面初始化控制,包括保持布局和状态、管理全局数据。同时,详细阐述了配置公共布局和全局样式的方法,以及自定义Document来修改HTML和head内容。此外,还提到了创建自定义404页面和通过Express设置开发服务器解决跨域问题。
摘要由CSDN通过智能技术生成

一、自定义App

1. 特性

Next.js 使用 App 组件来初始化页面。你可以覆盖该 App 组件并控制页面的初始化。这让你可以做一些操作,例如:

  • 页面切换之间保持布局的持久化
    • 其实就是在各页面之间保持部分布局始终存在,类似于之前在React根组件中写的tabbar、或者是公共的导航条之类的布局,并不会随着页面的切换而丢失这些布局。
  • 切换页面时保持状态(state)
    • 管理全局数据。
  • 使用 componentDidCatch 自定义错误处理
  • 向页面(pages)注入额外的数据
  • 添加全局 CSS 样式文件
    • 该文件可以导入自定义全局样式文件、第三方组件库样式文件

2. 配置公共布局及全局样式

  1. 首先创建 ./pages/_app.jsx 文件,添加如下代码:
    import "../app/globals.css"; // 引入自定义全局样式文件,样式即可全局生效
    
    // 自定义App组件,类似于传统的React项目中的根组件
    function App({ Component, pageProps }) {
      return (
        <>
          {/*添加公共导航:在每个 page 页面配置导航标题,那么公共导航就可以根据页面的title属性,配置当前导航内容。*/}
          <div className="nav">
            {pageProps.title ? pageProps.title : "公共导航"}
          </div>
          <Component {...pageProps}  data="额外的数据" />
        </>
      );
    }
    // 这个方法使得每一个页面都由服务器渲染,禁用了自动静态优化功能,所以只有应用中每个单独页面都有数据请求时才可以使用。
    // App.getInitialProps = async (appContext) => {
    //   const appProps = await App.getInitialProps(appContext)
    //    return { ...appProps }
    // }
    // 注意事项:
    // 1. 在 App 中添加自定义的 getInitialProps 时将禁用掉自动静态优化
    // 2. 在自定义的 App 中添加 getInitialProps 时,必须添加 import App from "next/app" 语句、 在 getInitialProps 内部调用 App.getInitialProps(appContext) 以及将返回的对象合并到返回值中
    
    export default App;
    
    • globals.css 全局文件需要在 _app.jsx 文件中导入才能生效。
    • Component 参数即当前展示的 page 页面,因此,每当你在路由之间切换时,Component 都会更新为新的 page。因此,你传递给 Component 的任何属性都将会被 page 接收到。
    • pageProps 参数是当前 page 页面,在 getServerSideProps 或者 getStaticProps 中请求到的数据,需要通过 {…pageProps} 的方式重新注入到当前 page 即:Component 组件。这有点类似于 React 高阶组件的用法。
    • 同时可以通过自定义prop属性(比如: data)向 page 页面注入额外的数据,供所有的 page 使用。

注意事项

  • _app.jsx 文件中的全局样式,针对 ./pages 目录 以及 `./app/page.jsx 首页文件都可以正常生效。
  • _app.jsx 文件中的公共布局页面,针对 ./pages 目录 下的所有页面都生效,但是 `./app/page.jsx 首页不生效,并没有出现公共导航页面内容。
  • 如果你对 App 组件进行了自定义时你的应用程序正在运行中,那么你需要重新启动开发服务器才能使修改生效。
  • 目前,App 不支持 Next.js 的 数据获取方法,例如 getStaticProps 或 getServerSideProps。
截图如下

在这里插入图片描述

  • app/layout.js 也导入了 app/global.css 文件,但是这里不是全局生效的,只针对 app/page.jsx 内部的元素生效,pages 下的组件不生效。

二、自定义Document

在 next 中,我们只需要关心页面的 body 内容部分即可,而不需要关心 <html><head> 这些标签的内容,next 服务端自动生成的一套统一的 html + head + body 结构就能满足开发需求。如果项目中需要向 head 头部加入一些其它的 css 文件或者是 js 文件,就需要通过自定义 _document.jsx 的方式实现,覆盖默认的文档结构。

因此,自定义 _app.jsx 是覆盖 body 中的内容,而 _document.jsx 则是对 head 和 html 元素的内容进行覆盖。

用法

  • 新建 ./pages/_document.jsx 文件,并添加内容:
    import Document, { Html, Head, Main, NextScript } from 'next/document'
    
    class MyDocument extends Document {
      static async getInitialProps(ctx) {
        const initialProps = await Document.getInitialProps(ctx)
        return { ...initialProps }
      }
    
      render() {
        return (
          <Html>
            <Head>
            	<meta charSet="utf-8" />
    	        <meta
    	           name="viewport"
    	           content="initial-scale=1.0, width=device-width"
    	        />
    	        <title>测试一下</title>
    		</Head>
            <body>
              <Main />
              <NextScript />
            </body>
          </Html>
        )
      }
    }
    
    export default MyDocument
    
    • 要正确渲染页面,<Html><Head/><Main/><NextScript/> 是必须要引入。
    • 需要在 yarn build 之后,通过 yarn start 才能看到自定义的文档内容,dev模式是看不到刚刚自定义的document内容的。
    • pages/_document.js 中添加 <title> 标签将导致 next/head 出现意外结果,因为_document.js仅在初始预渲染时渲染。官方不建议把 <title> 放到 _document.js 中。
    • page 页面的 title 标签,可以放在 _app.jsx 中统一配置:
      import Head from "next/head";
      function App({ Component, pageProps }) {
        return (
          <>
            <Head>
              <title>next学习</title>
            </Head>
            <Component {...pageProps} title="额外的数据" />
          </>
        );
      }
      
      export default App;
      
    • app/page.jsx 首页文件的 <title> 标题可以在根布局文件 app/layout.js 文件中配置
      export const metadata = {
        title: '首页', 
        description: 'Generated by create next app',
      }
      
      export default function RootLayout({ children }) {
        return (
          <html lang="en">
            <body>{children}</body>
          </html>
        )
      }
      

三、自定义404页面

  • pages 目录下新建 404.jsx 文件,文件名为固定,当存在不合法的路径时,就会返回该页面中的组件内容。
    export default function NotFound() {
      return <div>404</div>
    }
    

四、自定义开发服务器

通过自定义代理服务器,解决跨域问题。

  • 安装 express 和 http-proxy-middleware 包
    • yarn add express http-proxy-middleware
  • 在根目录下新建 server.js 文件,并添加如下内容
    const express = require("express");
    const next = require("next");
    const { createProxyMiddleware } = require("http-proxy-middleware");
    
    const devProxy = {
      "/api": { target: "目标地址", changeOrigin: true },
    };
    
    const dev = process.env.NODE_ENV !== "production";
    const app = next({ dev });
    const handle = app.getRequestHandler();
    
    app.prepare().then(() => {
      const app = express();
      if (dev && devProxy)
        Object.keys(devProxy).forEach(function (context) {
          app.use(createProxyMiddleware(context, devProxy[context]));
        });
      app.all("*", (req, res) => handle(req, res));
      app.listen(3000, (err) => {
        if (err) throw err;
        console.log(`> Ready on http://localhost:3000`);
      });
    });
    
  • 修改 package.json 文件
    "dev": "node server.js",
    
  • 重启服务器
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值