精华内容
下载资源
问答
  • next.js
    千次阅读
    2022-05-26 15:05:20

    创建Next.js应用程序

    要从头开始使用 React 构建完整的 Web 应用程序,您需要考虑许多重要的细节:

    • 代码必须使用 webpack 之类的打包器打包,并使用 Babel 之类的编译器进行转换。
    • 您需要进行生产优化,例如代码拆分。
    • 您可能希望静态预渲染某些页面以提高性能和 SEO。您可能还想使用服务器端渲染或客户端渲染。
    • 您可能需要编写一些服务器端代码来将您的 React 应用程序连接到您的数据存储。

    一个框架可以解决这些问题。但是这样的框架必须具有正确的抽象级别——否则它不会很有用。它还需要具有出色的“开发人员体验”,确保您和您的团队在编写代码时拥有令人惊叹的体验。

    Next.js:反应框架

    输入Next.js,即 React 框架。Next.js 为上述所有问题提供了解决方案。但更重要的是,它会让你和你的团队在构建 React 应用程序时进入成功的陷阱。

    Next.js 旨在拥有一流的开发人员体验和许多内置功能,例如:

    • 直观的基于页面的路由系统(支持动态路由)
    • 预渲染,静态生成(SSG) 和服务器端渲染(SSR) 均支持每页
    • 自动代码拆分以加快页面加载速度
    • 具有优化预取的客户端路由
    • 内置 CSS和Sass 支持,支持任何CSS-in-JS库
    • 支持快速刷新的开发环境
    • 使用无服务器函数构建 API 端点的API 路由
    • 完全可扩展

    Next.js 用于数以万计的面向生产的网站和 Web 应用程序,其中包括许多世界上最大的品牌。

    设置

    首先,让我们确保您的开发环境已准备就绪。

    • 如果您没有安装Node.js,请从此处安装。您需要 Node.js 版本10.13或更高版本。
    • 您将在本教程中使用自己的文本编辑器和终端应用程序。

    如果您使用的是 Windows,我们建议您下载 Git for Windows并使用它附带的 Git Bash,它支持本教程中特定于 UNIX 的命令。适用于 Linux 的 Windows 子系统 (WSL)是另一种选择。

    创建 Next.js 应用

    要创建 Next.js 应用程序,请打开终端,cd进入要在其中创建应用程序的目录,然后运行以下命令:

    npx create-next-app nextjs-blog --use-npm --example "https://github.com/vercel/next-learn/tree/master/basics/learn-starter"
    

    在后台,它使用名为 的工具create-next-app,它为您引导 Next.js 应用程序。它通过标志使用这个模板--example

    如果它不起作用,请查看此页面

    运行开发服务器

    您现在有一个名为nextjs-blog. 让我们cd进入它:

    cd nextjs-blog
    

    然后,运行以下命令:

    npm run dev
    

    这会在端口3000上启动 Next.js 应用程序的“开发服务器”。

    来到Next.js页面

    当我们访问http://localhost:3000时,会出现下面页面。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2PGof7bC-1653548710175)(../JavaScript学习笔记/javascript-learning-notes/images/9073cd41310845a5b89084aea48daddd.png)]

    编辑页面

    让我们尝试编辑起始页。

    • 确保 Next.js 开发服务器仍在运行。
    • pages/index.js使用您的文本编辑器打开。
    • 在标签下找到写着“Welcome to”<h1>的文字并将其更改为“Learn”。
    • 保存文件。

    保存文件后,浏览器会自动使用新文本更新页面:
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r8DljBZ0-1653548710176)(../JavaScript学习笔记/javascript-learning-notes/images/afb2ce9db913485fa12e033ab3822542.png)]

    Next.js 开发服务器启用了快速刷新。当您对文件进行更改时,Next.js 几乎会立即自动在浏览器中应用更改。无需刷新!这将帮助您快速迭代您的应用程序。

    在页面之间导航

    Next.js中的页面

    pages在 Next.js 中,页面是从目录中的文件导出的 React 组件。

    页面根据其文件名与路由相关联。例如,在开发中:

    • pages/index.js/路线相关联。
    • pages/posts/first-post.js/posts/first-post路线相关联。

    我们已经有了这个pages/index.js文件,所以让我们创建pages/posts/first-post.js来看看它是如何工作的。

    创建一个新页面

    在.posts_pages

    first-post.js在目录中创建一个名为的文件posts,其内容如下:

    export default function FirstPost() {
      return <h1>First Post</h1>;
    }
    

    组件可以有任何名称,但您必须将其导出为default导出。

    现在,确保开发服务器正在运行并访问http://localhost:3000/posts/first-post。您应该看到以下页面:
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0ZIzpqFU-1653548710177)(../JavaScript学习笔记/javascript-learning-notes/images/6f616b255bcc4c9680cdc9f271f5e144.png)]

    这就是在 Next.js 中创建不同页面的方法。

    pages只需在目录下创建一个JS文件,文件的路径就变成了URL路径。

    在某种程度上,这类似于使用 HTML 或 PHP 文件构建网站。您无需编写 HTML,而是编写 JSX 并使用 React 组件。

    让我们添加一个指向新添加页面的链接,以便我们可以从主页导航到它。

    链接组件

    在网站上的页面之间链接时,您使用<a>HTML 标记。

    在 Next.js 中,您使用LinkComponent fromnext/link来包装<a>标签。<Link>允许您进行客户端导航到应用程序中的不同页面。

    使用<Link>

    首先,打开,并通过在顶部添加以下行来pages/index.js导入Link组件:next/link

    import Link from 'next/link';
    

    然后找到h1看起来像这样的标签:

    <h1 className="title">
      Learn <a href="https://nextjs.org">Next.js!</a>
    </h1>
    

    并将其更改为:

    <h1 className="title">
      Read{' '}
      <Link href="/posts/first-post">
        <a>this page!</a>
      </Link>
    </h1>
    

    {' '}添加一个空格,用于将文本分成多行。

    接下来,打开pages/posts/first-post.js并将其内容替换为以下内容:

    import Link from 'next/link';
    
    export default function FirstPost() {
      return (
        <>
          <h1>First Post</h1>
          <h2>
            <Link href="/">
              <a>Back to home</a>
            </Link>
          </h2>
        </>
      );
    }
    

    如您所见,该Link组件类似于使用标签,但您使用并在其中放置标签而不是 。

    让我们看看它是否有效。您现在应该在每个页面上都有一个链接,允许您来回切换:
    在这里插入图片描述

    客户端导航

    Link组件支持在同一个 Next.js 应用程序中的两个页面之间进行客户端导航。

    客户端导航意味着使用 JavaScript进行页面转换,这比浏览器完成的默认导航要快。

    这里有一个简单的方法可以验证它:

    • 使用浏览器的开发者工具将backgroundCSS 属性更改<html>yellow
    • 单击链接可在两个页面之间来回切换。
    • 您会看到黄色背景在页面转换之间持续存在。

    这表明浏览器没有加载整个页面并且客户端导航正在工作。
    在这里插入图片描述

    如果您使用<a href="…">而不是<Link href="…">这样做,则背景颜色将在链接点击时被清除,因为浏览器会进行完全刷新。

    代码拆分和预取

    Next.js 会自动进行代码拆分,因此每个页面只加载该页面所需的内容。这意味着在呈现主页时,最初不会提供其他页面的代码。

    即使您有数百个页面,这也可以确保主页快速加载。

    仅加载您请求的页面的代码也意味着页面变得孤立。如果某个页面抛出错误,应用程序的其余部分仍然可以工作。

    此外,在 Next.js 的生产版本中,每当Link组件出现在浏览器的视口中时,Next.js 都会自动在后台预取链接页面的代码。当您单击链接时,目标页面的代码已经在后台加载,页面转换几乎是即时的!

    概括

    Next.js 通过代码拆分、客户端导航和预取(在生产中)自动优化您的应用程序以获得最佳性能。

    您将路由创建为文件pages并使用内置Link组件。不需要路由库。

    您可以在路由文档中的 API 参考和路由中了解有关Link组件的更多信息。next/link

    如果您需要链接到Next.js 应用程序之外的外部页面,只需使用<a>不带Link.如果您需要添加属性,例如,className将其添加到a标签,而不是Link标签。这是一个例子。

    资产、元数据和 CSS

    资产

    Next.js 可以在顶级目录下提供静态资产,例如图片。可以从应用程序的根目录引用其中的文件,类似于.public public pages

    public目录对于robots.txt、Google Site Verification 和任何其他静态资产也很有用。查看静态文件服务的文档以了解更多信息。

    下载您的个人资料图片

    首先,让我们检索您的个人资料图片。

    • .jpg以格式下载您的个人资料图片(或使用此文件)。

    • images在目录中创建一个public目录。

    • 将图片另存为profile.jpg目录public/images

    • 图像大小可以在 400 像素 x 400 像素左右。

    • 您可以直接删除该public目录下未使用的 SVG 徽标文件。

    未优化的图像

    使用常规 HTML,您将添加您的个人资料图片,如下所示:

    <img src="/images/profile.jpg" alt="Your Name" />
    

    但是,这意味着您必须手动处理:

    • 确保您的图像在不同的屏幕尺寸上响应
    • 使用第三方工具或库优化您的图像
    • 仅在图像进入视口时加载图像

    和更多。相反,Next.js 提供了一个Image开箱即用的组件来为您处理这个问题。

    图像成分和图像优化

    next/image是 HTML<img>元素的扩展,是为现代网络发展而来的。

    Next.js 默认还支持图像优化。这允许在浏览器支持时以WebP等现代格式调整、优化和提供图像。这避免了将大图像传送到具有较小视口的设备。它还允许 Next.js 自动采用未来的图像格式并将它们提供给支持这些格式的浏览器。

    自动图像优化适用于任何图像源。即使图像由外部数据源(如 CMS)托管,它仍然可以进行优化。

    使用图像组件

    Next.js 不是在构建时优化图像,而是在用户请求时按需优化图像。与静态站点生成器和纯静态解决方案不同,您的构建时间不会增加,无论是发送 10 个图像还是 1000 万个图像。

    默认情况下,图像是延迟加载的。这意味着您的页面速度不会因视口之外的图像而受到惩罚。图像在滚动到视口时加载。

    图像总是以这样的方式呈现,以避免累积布局移位,这是谷歌将在搜索排名中使用的核心网络生命力

    这是一个next/image用于显示我们的个人资料图片的示例。heightwidth道具应该是所需的渲染大小,具有与源图像相同的纵横比。

    **注意:**我们稍后将在“抛光布局”中使用该组件,无需复制它。

    import Image from 'next/image';
    
    const YourComponent = () => (
      <Image
        src="/images/profile.jpg" // Route of the image file
        height={144} // Desired size with correct aspect ratio
        width={144} // Desired size with correct aspect ratio
        alt="Your Name"
      />
    );
    

    元数据

    如果我们想修改页面的元数据,比如<title>HTML 标签,该怎么办?

    <title><head>HTML 标签的一部分,所以让我们深入研究如何<head>在 Next.js 页面中修改标签。

    在编辑器中打开pages/index.js并找到以下行:

    <Head>
      <title>Create Next App</title>
      <link rel="icon" href="/favicon.ico" />
    </Head>
    

    请注意,<Head>使用 代替小写<head><Head>是一个内置在 Next.js 中的 React 组件。它允许您修改<head>页面的。

    Head您可以从模块中导入组件next/head

    添加Headfirst-post.js

    我们还没有添加<title>到我们的/posts/first-post路线。让我们添加一个。

    打开文件并在文件开头添加frompages/posts/first-post.js的导入:Headnext/head

    import Head from 'next/head';
    

    然后,更新导出的FirstPost组件以包含该Head组件。现在,我们将只添加title标签:

    export default function FirstPost() {
      return (
        <>
          <Head>
            <title>First Post</title>
          </Head>
          <h1>First Post</h1>
          <h2>
            <Link href="/">
              <a>Back to home</a>
            </Link>
          </h2>
        </>
      );
    }
    

    第三方 JavaScript

    第三方 JavaScript是指从第三方来源添加的任何脚本。通常,包含第三方脚本是为了将更新的功能引入不需要从头开始编写的站点,例如分析、广告和客户支持小部件。

    添加第三方 JavaScript

    让我们深入研究如何将第三方脚本添加到 Next.js 页面。

    在编辑器中打开pages/posts/first-post.js并找到以下行:

    <Head>
      <title>First Post</title>
    </Head>
    

    除了元数据,需要尽快加载和执行的脚本通常被添加到<head>页面中。使用常规 HTML<script>元素,将添加一个外部脚本,如下所示:

    <Head>
      <title>First Post</title>
      <script src="https://connect.facebook.net/en_US/sdk.js" />
    </Head>
    

    该脚本包含Facebook SDK ,通常用于引入 Facebook 社交插件和其他功能。尽管这种方法有效,但以这种方式包含脚本并不能清楚地知道何时加载相对于在同一页面上获取的其他 JavaScript 代码。如果一个特定的脚本是渲染阻塞的并且会延迟页面内容的加载,这会显着影响性能。

    使用脚本组件

    next/script是 HTML<script>元素的扩展,并在获取和执行其他脚本时进行优化。

    在同一个文件中,在文件开头添加一个 import for Scriptfrom next/script

    import Script from 'next/script';
    

    现在,更新FirstPost组件以包含该Script组件:

    export default function FirstPost() {
      return (
        <>
          <Head>
            <title>First Post</title>
          </Head>
          <Script
            src="https://connect.facebook.net/en_US/sdk.js"
            strategy="lazyOnload"
            onLoad={() =>
              console.log(`script loaded correctly, window.FB has been populated`)
            }
          />
          <h1>First Post</h1>
          <h2>
            <Link href="/">
              <a>Back to home</a>
            </Link>
          </h2>
        </>
      );
    }
    

    请注意,脚本组件中定义了一些附加属性:

    • strategy控制何时加载第三方脚本。值lazyOnload告诉 Next.js 在浏览器空闲时间延迟加载此特定脚本
    • onLoad用于在脚本完成加载后立即运行任何 JavaScript 代码。在此示例中,我们将一条消息记录到控制台,指出脚本已正确加载

    尝试访问http://localhost:3000/posts/first-post。通过使用浏览器的开发人员工具,您应该会在Console 面板中看到上面记录的消息。此外,您可以运行window.FB以查看脚本已填充此全局变量。

    注意: Facebook SDK 只是作为一个人为的示例来展示如何以高性能的方式将第三方脚本添加到您的应用程序中。现在您已了解在 Next.js 中包含第三方功能的基础知识,您可以FirstPost在继续之前删除 Script 组件。

    要了解有关该Script组件的更多信息,请查看文档

    CSS样式

    现在让我们谈谈CSS 样式

    如您所见,我们的索引页面 ( http://localhost:3000 ) 已经有了一些样式。如果您看一下pages/index.js,您应该会看到如下代码:

    <style jsx>{`
      …
    `}</style>
    

    该页面使用了一个名为styled-jsx的库。它是一个“CSS-in-JS”库——它允许您在 React 组件中编写 CSS,并且 CSS 样式将被限定(其他组件不会受到影响)。

    Next.js 内置了对styled-jsx的支持,但您也可以使用其他流行的 CSS-in-JS 库,例如styled-componentsEmotion

    编写和导入 CSS

    Next.js内置了对 CSS和 Sass 的支持,允许您导入.css.scss文件。

    还支持使用流行的 CSS 库,例如Tailwind CSS 。

    在本课中,我们将讨论如何在 Next.js 中编写和导入 CSS 文件。我们还将讨论 Next.js 对CSS ModulesSass的内置支持。让我们潜入吧!

    上一页下一个

    布局组件

    首先,让我们创建一个Layout组件,它将在所有页面之间共享。

    • 创建一个名为components.
    • 在里面components,创建一个名为的文件layout.js,内容如下:
    export default function Layout({ children }) {
      return <div>{children}</div>;
    }
    

    然后,打开pages/posts/first-post.js,为组件添加一个导入Layout,并将其设为最外层组件:

    import Head from 'next/head';
    import Link from 'next/link';
    import Layout from '../../components/layout';
    
    export default function FirstPost() {
      return (
        <Layout>
          <Head>
            <title>First Post</title>
          </Head>
          <h1>First Post</h1>
          <h2>
            <Link href="/">
              <a>Back to home</a>
            </Link>
          </h2>
        </Layout>
      );
    }
    

    添加 CSS

    现在,让我们为Layout组件添加一些样式。为此,我们将使用CSS Modules,它允许您在 React 组件中导入 CSS 文件。

    创建一个名为的文件components/layout.module.css,其内容如下:

    .container {
      max-width: 36rem;
      padding: 0 1rem;
      margin: 3rem auto 6rem;
    }
    

    **重要提示:**要使用CSS 模块,CSS 文件名必须以.module.css.

    要在里面使用这个containercomponents/layout.js,你需要:

    • 导入 CSS 文件并为其分配一个名称,例如styles
    • styles.container用作_className

    打开components/layout.js并将其内容替换为以下内容:

    import styles from './layout.module.css';
    
    export default function Layout({ children }) {
      return <div className={styles.container}>{children}</div>;
    }
    

    如果您现在访问http://localhost:3000/posts/first-post,您应该会看到文本现在位于居中的容器中:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WeOxyRyf-1653549168961)(images/layout.png)]

    自动生成唯一的类名

    现在,如果您查看浏览器的 devtools 中的 HTML,您会注意到组件div呈现Layout的类名如下所示layout_container__...

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-M9HNvFbB-1653549168962)(images/devtools.png)]

    这就是CSS 模块所做的:它会自动生成唯一的类名。只要您使用 CSS Modules,您就不必担心类名冲突。

    此外,Next.js 的代码拆分功能也适用于CSS 模块。它确保为每个页面加载最少量的 CSS。这导致更小的包大小。

    CSS 模块在构建时从 JavaScript 包中提取,并生成.css由 Next.js 自动加载的文件。

    全局样式

    CSS 模块对于组件级样式很有用。但是,如果您希望每个页面都加载一些 CSS ,Next.js 也对此提供支持。

    要加载全局 CSS文件,请创建一个名为的文件pages/_app.js,其内容如下:

    export default function App({ Component, pageProps }) {
      return <Component {...pageProps} />;
    }
    

    App组件是所有不同页面通用的顶级组件。例如,您可以使用此App组件在页面之间导航时保持状态。

    重启开发服务器

    **重要提示:**添加时需要重启开发服务器pages/_app.js。按Ctrl + c停止服务器并运行:

    npm run dev
    

    添加全局 CSS

    在 Next.js 中,您可以通过pages/_app.js. 您不能在其他任何地方导入全局 CSS。

    全局 CSS无法导入外部的原因pages/_app.js是全局 CSS 会影响页面上的所有元素。

    如果您要从主页导航到/posts/first-post页面,则主页中的全局样式会/posts/first-post无意中产生影响。

    您可以将全局 CSS 文件放置在任何位置并使用任何名称。因此,让我们执行以下操作:

    • 创建一个顶级styles目录并global.css在里面创建。
    • 将以下内容添加到styles/global.css. 它会重置一些样式并更改a标签的颜色:
    html,
    body {
      padding: 0;
      margin: 0;
      font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu,
        Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
      line-height: 1.6;
      font-size: 18px;
    }
    
    * {
      box-sizing: border-box;
    }
    
    a {
      color: #0070f3;
      text-decoration: none;
    }
    
    a:hover {
      text-decoration: underline;
    }
    
    img {
      max-width: 100%;
      display: block;
    }
    

    最后,pages/_app.js像这样打开添加导入 CSS 文件:

    import '../styles/global.css';
    
    export default function App({ Component, pageProps }) {
      return <Component {...pageProps} />;
    }
    

    现在,如果您访问http://localhost:3000/posts/first-post,您将看到样式已应用:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1mKlb7Op-1653549168964)(images/global-styles.png)]

    如果它不起作用:确保在添加时重新启动开发服务器pages/_app.js

    抛光布局

    到目前为止,我们只添加了最少的 React 和 CSS 代码来说明诸如CSS 模块之类的概念。在我们继续下一节关于数据获取的课程之前,让我们完善一下我们的页面样式和代码。

    更新components/layout.module.css

    首先,打开components/layout.module.css并用以下更精美的布局和个人资料图片样式替换其内容:

    .container {
      max-width: 36rem;
      padding: 0 1rem;
      margin: 3rem auto 6rem;
    }
    
    .header {
      display: flex;
      flex-direction: column;
      align-items: center;
    }
    
    .backToHome {
      margin: 3rem 0 0;
    }
    

    创造styles/utils.module.css

    其次,让我们创建一组实用的 CSS 类,用于排版和其他将在多个组件中有用的类。

    让我们添加一个名为styles/utils.module.css以下内容的新 CSS 文件:

    .heading2Xl {
      font-size: 2.5rem;
      line-height: 1.2;
      font-weight: 800;
      letter-spacing: -0.05rem;
      margin: 1rem 0;
    }
    
    .headingXl {
      font-size: 2rem;
      line-height: 1.3;
      font-weight: 800;
      letter-spacing: -0.05rem;
      margin: 1rem 0;
    }
    
    .headingLg {
      font-size: 1.5rem;
      line-height: 1.4;
      margin: 1rem 0;
    }
    
    .headingMd {
      font-size: 1.2rem;
      line-height: 1.5;
    }
    
    .borderCircle {
      border-radius: 9999px;
    }
    
    .colorInherit {
      color: inherit;
    }
    
    .padding1px {
      padding-top: 1px;
    }
    
    .list {
      list-style: none;
      padding: 0;
      margin: 0;
    }
    
    .listItem {
      margin: 0 0 1.25rem;
    }
    
    .lightText {
      color: #666;
    }
    

    更新components/layout.js

    第三,打开components/layout.js并将其内容替换为以下代码,更改 Your Name为实际名称:

    import Head from 'next/head';
    import Image from 'next/image';
    import styles from './layout.module.css';
    import utilStyles from '../styles/utils.module.css';
    import Link from 'next/link';
    
    const name = 'Your Name';
    export const siteTitle = 'Next.js Sample Website';
    
    export default function Layout({ children, home }) {
      return (
        <div className={styles.container}>
          <Head>
            <link rel="icon" href="/favicon.ico" />
            <meta
              name="description"
              content="Learn how to build a personal website using Next.js"
            />
            <meta
              property="og:image"
              content={`https://og-image.vercel.app/${encodeURI(
                siteTitle,
              )}.png?theme=light&md=0&fontSize=75px&images=https%3A%2F%2Fassets.vercel.com%2Fimage%2Fupload%2Ffront%2Fassets%2Fdesign%2Fnextjs-black-logo.svg`}
            />
            <meta name="og:title" content={siteTitle} />
            <meta name="twitter:card" content="summary_large_image" />
          </Head>
          <header className={styles.header}>
            {home ? (
              <>
                <Image
                  priority
                  src="/images/profile.jpg"
                  className={utilStyles.borderCircle}
                  height={144}
                  width={144}
                  alt={name}
                />
                <h1 className={utilStyles.heading2Xl}>{name}</h1>
              </>
            ) : (
              <>
                <Link href="/">
                  <a>
                    <Image
                      priority
                      src="/images/profile.jpg"
                      className={utilStyles.borderCircle}
                      height={108}
                      width={108}
                      alt={name}
                    />
                  </a>
                </Link>
                <h2 className={utilStyles.headingLg}>
                  <Link href="/">
                    <a className={utilStyles.colorInherit}>{name}</a>
                  </Link>
                </h2>
              </>
            )}
          </header>
          <main>{children}</main>
          {!home && (
            <div className={styles.backToHome}>
              <Link href="/">
                <a>← Back to home</a>
              </Link>
            </div>
          )}
        </div>
      );
    }
    

    以下是新内容:

    • meta标签(如og:image),用于描述页面的内容
    • 布尔home属性,它将调整标题和图像的大小
    • home如果是,底部的“返回主页”链接false
    • 添加了带有 的图像next/image,这些图像预加载了优先级属性
    import Head from 'next/head';
    import Layout, { siteTitle } from '../components/layout';
    import utilStyles from '../styles/utils.module.css';
    
    export default function Home() {
      return (
        <Layout home>
          <Head>
            <title>{siteTitle}</title>
          </Head>
          <section className={utilStyles.headingMd}>
            <p>[Your Self Introduction]</p>
            <p>
              (This is a sample website - you’ll be building a site like this on{' '}
              <a href="https://nextjs.org/learn">our Next.js tutorial</a>.)
            </p>
          </section>
        </Layout>
      );
    }
    

    然后换成[Your Self Introduction]你的自我介绍。以下是作者个人资料的示例:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ydnZmdaf-1653549168964)(images/image-20220523144320010.png)]

    就是这样!我们现在已经有了完善的布局代码,可以继续我们的数据获取课程。

    造型技巧

    以下是一些可能有用的样式提示。

    您只需阅读以下部分即可。无需对我们的应用程序进行更改!

    使用classnames库切换类

    classnames是一个简单的库,可让您轻松切换类名。您可以使用npm install classnames或安装它yarn add classnames

    请查看其文档以获取更多详细信息,但这是基本用法:

    • 假设您要创建一个Alert接受 的组件type,它可以是'success''error'
    • 如果是'success',则您希望文本颜色为绿色。如果是'error',您希望文本颜色为红色。

    您可以先编写一个 CSS 模块(例如alert.module.css),如下所示:

    .success {
      color: green;
    }
    .error {
      color: red;
    }
    

    classnames像这样使用:

    import styles from './alert.module.css';
    import cn from 'classnames';
    
    export default function Alert({ children, type }) {
      return (
        <div
          className={cn({
            [styles.success]: type === 'success',
            [styles.error]: type === 'error',
          })}
        >
          {children}
        </div>
      );
    }
    

    自定义 PostCSS 配置

    开箱即用,无需配置,Next.js 使用 PostCSS 编译CSS

    要自定义 PostCSS 配置,您可以创建一个名为postcss.config.js. 如果您使用Tailwind CSS 之类的库,这将非常有用。

    以下是添加Tailwind CSS的步骤。首先,安装软件包:

    npm install -D tailwindcss autoprefixer postcss
    

    然后,创建一个postcss.config.js

    // postcss.config.js
    module.exports = {
      plugins: {
        tailwindcss: {},
        autoprefixer: {},
      },
    };
    

    我们还建议通过指定以下选项来配置内容源content``tailwind.config.js

    // tailwind.config.js
    module.exports = {
      content: [
        './pages/**/*.{js,ts,jsx,tsx}',
        './components/**/*.{js,ts,jsx,tsx}',
        // For the best performance and to avoid false positives,
        // be as specific as possible with your content configuration.
      ],
    };
    

    要了解有关自定义 PostCSS 配置的更多信息,请查看PostCSS 的文档

    要轻松开始使用 Tailwind CSS,请查看我们的示例

    使用 Sass

    开箱即用,Next.js 允许您使用和扩展导入Sass 。你可以通过CSS 模块和or扩展来使用组件级 Sass 。.scss``.sass``.module.scss``.module.sass

    在您可以使用 Next.js 的内置 Sass 支持之前,请务必安装sass

    npm install -D sass
    

    预渲染和数据获取

    预渲染

    Next.js会提前为每个页面生成 HTML,而不是全部由客户端 JavaScript 完成。预渲染可以带来更好的性能和SEO

    每个生成的 HTML 都与该页面所需的最少 JavaScript 代码相关联。当浏览器加载页面时,其 JavaScript 代码将运行并使页面完全交互。(这个过程称为水合作用。)

    两种形式的预渲染

    Next.js 有两种预渲染形式:静态生成服务器端渲染。不同之处在于它何时为页面生成 HTML。

    • 静态生成是在构建时生成 HTML 的预渲染方法。然后在每个请求上重用预呈现的 HTML
    • 服务器端渲染是在每个请求上生成 HTML 的预渲染方法。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8U7mM6mj-1653549168975)(images/static-generation.png)]
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T5sy1v1I-1653549168976)(images/server-side-rendering.png)]

    在开发模式下(当您运行npm run dev或时yarn dev),每个页面都会在每个请求上预渲染——即使对于使用静态生成的页面也是如此。

    每页基础

    Next.js允许选择用于每个页面的预渲染方式。可以通过对大多数页面使用静态生成并为其他页面使用服务器端渲染来创建“混合”Next.js应用程序。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1myHL4NK-1653549168976)(images/per-page-basis.png)]

    何时使用静态生成服务器端渲染

    我们建议尽可能使用静态生成(有数据和无数据),因为您的页面可以构建一次并由 CDN 提供服务,这比让服务器在每次请求时呈现页面要快得多。

    您可以将静态生成用于多种类型的页面,包括:

    • 营销页面
    • 博客文章
    • 电子商务产品列表
    • 帮助和文档

    如果在用户请求之前需要预渲染此页面,那么就用静态生成

    如果用户不需要则的话使用静态生成会造成页面显示频繁更新数据,并且页面内容会随每个请求而更改,在这种情况下使用服务器端渲染

    有数据和无数据的静态生成

    静态生成可以在有数据和没有数据的情况下完成。

    到目前为止,我们创建的所有页面都不需要获取外部数据。当应用程序为生产而构建时,这些页面将自动静态生成。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rOpxvh6t-1653549168977)(images/static-generation-without-data.png)]

    但是,对于某些页面,如果不先获取一些外部数据,您可能无法呈现 HTML。也许您需要在构建时访问文件系统、获取外部 API 或查询数据库。Next.js 开箱即用地支持这种情况——带数据的静态生成

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c72hQG24-1653549168977)(images/static-generation-with-data.png)]

    使用数据进行静态生成getStaticProps

    它是如何工作的?那么,在 Next.js 中,当你导出一个页面组件时,你也可以导出一个async名为getStaticProps. 如果你这样做,那么:

    • getStaticProps在生产中的构建时运行,并且…
    • 在函数内部,您可以获取外部数据并将其作为道具发送到页面。
    export default function Home(props) { ... }
    
    export async function getStaticProps() {
      // Get external data from the file system, API, DB, etc.
      const data = ...
    
      // The value of the `props` key will be
      //  passed to the `Home` component
      return {
        props: ...
      }
    }
    

    本质上,getStaticProps它允许你告诉 Next.js:“嘿,这个页面有一些数据依赖——所以当你在构建时预渲染这个页面时,一定要先解决它们!”

    注意:在开发模式下,getStaticProps改为在每个请求上运行。

    博客数据

    我们现在将使用文件系统将博客数据添加到我们的应用程序中。每篇博文都将是一个降价文件。

    • 创建一个名为的新顶级目录**posts**(这与 不同pages/posts)。
    • 在 内部posts,创建两个文件:pre-rendering.mdssg-ssr.md.

    现在,将以下代码复制到posts/pre-rendering.md

    ---
    title: 'Two Forms of Pre-rendering'
    date: '2020-01-01'
    ---
    
    Next.js has two forms of pre-rendering: **Static Generation** and **Server-side Rendering**. The difference is in **when** it generates the HTML for a page.
    
    - **Static Generation** is the pre-rendering method that generates the HTML at **build time**. The pre-rendered HTML is then _reused_ on each request.
    - **Server-side Rendering** is the pre-rendering method that generates the HTML on **each request**.
    
    Importantly, Next.js lets you **choose** which pre-rendering form to use for each page. You can create a "hybrid" Next.js app by using Static Generation for most pages and using Server-side Rendering for others.
    

    然后,将以下代码复制到posts/ssg-ssr.md

    ---
    title: 'When to Use Static Generation v.s. Server-side Rendering'
    date: '2020-01-02'
    ---
    
    We recommend using **Static Generation** (with and without data) whenever possible because your page can be built once and served by CDN, which makes it much faster than having a server render the page on every request.
    
    You can use Static Generation for many types of pages, including:
    
    - Marketing pages
    - Blog posts
    - E-commerce product listings
    - Help and documentation
    
    You should ask yourself: "Can I pre-render this page **ahead** of a user's request?" If the answer is yes, then you should choose Static Generation.
    
    On the other hand, Static Generation is **not** a good idea if you cannot pre-render a page ahead of a user's request. Maybe your page shows frequently updated data, and the page content changes on every request.
    
    In that case, you can use **Server-Side Rendering**. It will be slower, but the pre-rendered page will always be up-to-date. Or you can skip pre-rendering and use client-side JavaScript to populate data.
    

    您可能已经注意到,每个 Markdown 文件的顶部都有一个元数据部分,其中包含titledate. 这称为 YAML Front Matter,可以使用名为gray-matter的库进行解析。

    解析博客数据getStaticProps

    pages/index.js现在,让我们使用这些数据更新我们的索引页面 ( )。我们想:

    • 解析每个 markdown 文件并获取titledate和文件名(将用作id发布 URL)。
    • 列出索引页上的数据,按日期排序。

    要在预渲染中执行此操作,我们需要实现getStaticProps.

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Rcp8qEjM-1653549168978)(images/index-page.png)]

    实现 getStaticProps

    首先,安装gray-matter,它可以让我们解析每个 markdown 文件中的元数据。

    npm install gray-matter
    

    接下来,我们将创建一个简单的库,用于从文件系统中获取数据。

    • 创建一个名为lib
    • 在里面lib,创建一个名为的文件posts.js,内容如下
    import fs from 'fs';
    import path from 'path';
    import matter from 'gray-matter';
    
    const postsDirectory = path.join(process.cwd(),'posts');//process.cwd()此方法不接受任何参数,此方法返回一个字符串,该字符串指定node.js进程的当前工作目录。
    
    export function getSortedPostsData() {
      // 在/posts下获取文件名
      const fileNames = fs.readdirSync(postsDirectory);
      const allPostsData = fileNames.map((fileName) => {
        // 从文件名中删除“.md”以获取id
        const id = fileName.replace(/\.md$/,'');
    
        // 将标记文件读取为字符串
        const fullPath = path.join(postsDirectory,fileName);
        const fileContents = fs.readFileSync(fullPath,'utf8');
    
        // 使用gray-matter分析post元数据部分
        const matterResult = matter(fileContents);
        console.log(matterResult.data);
        // 将数据与id组合
        return {
          id,
          ...matterResult.data,
        };
      });
    
      // 按日期对帖子排序
      return allPostsData.sort(({date:a},{date:b}) => {
        if (a < b) {
          return 1;
        } else if (a > b) {
          return -1;
        } else {
          return 0;
        }
      })
    }
    

    **注意:**在 Next.js 中,lib文件夹没有像pages文件夹一样的指定名称,因此您可以将其命名为任何名称。通常习惯使用libor utils

    现在,我们需要添加一个 import for并在getSortedPostsData里面调用它。getStaticPropspages/index.js

    在您的编辑器中打开并在导出的组件pages/index.js上方添加以下代码:Home

    import { getSortedPostsData } from '../lib/posts';
    
    export async function getStaticProps() {
      const allPostsData = getSortedPostsData();
      return {
        props: {
          allPostsData,
        },
      };
    }
    

    通过在 中的对象allPostsData内部返回,博客文章将作为道具传递给组件。现在您可以像这样访问博客文章:props``getStaticProps``Home

    export default function Home ({ allPostsData }) { ... }
    

    要显示博客文章,让我们更新Home组件以添加另一个<section>标签,其中包含您的自我介绍部分下方的数据。不要忘记也将道具从更改()({ allPostsData })

    export default function Home({ allPostsData }) {
      return (
        <Layout home>
          {/* Keep the existing code here */}
    
          {/* Add this <section> tag below the existing <section> tag */}
          <section className={`${utilStyles.headingMd} ${utilStyles.padding1px}`}>
            <h2 className={utilStyles.headingLg}>Blog</h2>
            <ul className={utilStyles.list}>
              {allPostsData.map(({ id, date, title }) => (
                <li className={utilStyles.listItem} key={id}>
                  {title}
                  <br />
                  {id}
                  <br />
                  {date}
                </li>
              ))}
            </ul>
          </section>
        </Layout>
      );
    }
    

    如果您访问http://localhost:3000 ,您现在应该会看到博客数据。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W2yTKxga-1653549168978)(images/blog-data.png)]

    已经成功地(从文件系统)获取了外部数据并使用这些数据预渲染了索引页面。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OSpkNrjZ-1653549168979)(images/index-page-16533813833993.png)]

    getStaticProps 详细信息

    以下是您应该了解的一些基本信息getStaticProps

    获取外部 API 或查询数据库

    lib/posts.js中,我们已经实现getSortedPostsData了从文件系统中获取数据。但是您可以从其他来源获取数据,例如外部 API 端点,它会正常工作:

    export async function getSortedPostsData() {
      // Instead of the file system,
      // fetch post data from an external API endpoint
      const res = await fetch('..');
      return res.json();
    }
    

    注意fetch():客户端和服务器上的Next.js polyfills 。你不需要导入它。

    也可以直接查询数据库:

    import someDatabaseSDK from 'someDatabaseSDK'
    
    const databaseClient = someDatabaseSDK.createClient(...)
    
    export async function getSortedPostsData() {
      // Instead of the file system,
      // fetch post data from a database
      return databaseClient.query('SELECT posts...')
    }
    

    这是可能的,因为getStaticProps在服务器端运行。它永远不会在客户端运行。它甚至不会包含在浏览器的 JS 包中。这意味着您可以编写诸如直接数据库查询之类的代码,而无需将它们发送到浏览器。

    开发与生产

    因为它打算在构建时运行,所以您将无法使用仅在请求期间可用的数据,例如查询参数或 HTTP 标头。

    仅允许在页面中

    getStaticProps只能从页面导出。您不能从非页面文件中导出它。

    这种限制的原因之一是 React 需要在呈现页面之前拥有所有必需的数据。

    如果我需要在请求时获取数据怎么办?

    如果您不能在用户请求之前预渲染页面,则静态生成不是一个好主意。也许您的页面会显示频繁更新的数据,并且页面内容会随每个请求而更改。

    在这种情况下,您可以尝试服务器端渲染或跳过预渲染。

    在请求时获取数据

    如果您需要在请求时而不是在构建时获取数据,您可以尝试服务器端渲染

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-n1Hgp5N1-1653549168979)(images/server-side-rendering-with-data.png)]

    要使用服务器端渲染,您需要导出getServerSideProps而不是getStaticProps从页面导出。

    使用getServerSideProps

    这是getServerSideProps. 对于我们的博客示例来说,这不是必需的,因此我们不会实现它。

    export async function getServerSideProps(context) {
      return {
        props: {
          // props for your component
        },
      };
    }
    

    因为getServerSideProps是在请求时调用的,所以它的参数(context)包含了请求特定的参数。

    getServerSideProps仅当您需要预渲染必须在请求时获取其数据的页面时才应使用。第一个字节的时间(TTFB)会比getStaticProps因为服务器必须计算每个请求的结果要慢,并且如果没有额外的配置, CDN无法缓存结果。

    客户端渲染

    如果您不需要预先渲染数据,您还可以使用以下策略(称为Client-side Rendering):

    • 静态生成(预渲染)页面的不需要外部数据的部分。
    • 当页面加载时,使用 JavaScript 从客户端获取外部数据并填充剩余部分。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-M2k5K7r9-1653549168980)(images/client-side-rendering.png)]

    例如,这种方法适用于用户仪表板页面。因为仪表板是私有的、特定于用户的页面,所以 SEO 不相关,并且该页面不需要预渲染。数据经常更新,这需要在请求时获取数据。

    驻波比

    Next.js 背后的团队创建了一个名为SWR的用于数据获取的 React 钩子。如果您在客户端获取数据,我们强烈推荐它。它处理缓存、重新验证、焦点跟踪、间隔重新获取等。我们不会在这里详细介绍,但这里有一个示例用法:

    import useSWR from 'swr';
    
    function Profile() {
      const { data, error } = useSWR('/api/user', fetch);
    
      if (error) return <div>failed to load</div>;
      if (!data) return <div>loading...</div>;
      return <div>hello {data.name}!</div>;
    }
    

    查看SWR 文档以了解更多信息。

    动态路线

    页面路径取决于外部数据

    在上一课中,我们介绍了页面内容依赖于外部数据的情况。我们曾经getStaticProps获取所需的数据来呈现索引页面。

    在本课中,我们将讨论每个页面路径都依赖于外部数据的情况。Next.js 允许您使用依赖于外部数据的路径静态生成页面。这会在 Next.js 中启用动态 URL 。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vdTixGsU-1653549168980)(images/page-path-external-data.png)]

    如何使用动态路由静态生成页面

    在我们的例子中,我们想为博客文章创建动态路由:

    • 我们希望每个帖子都有 path /posts/<id>,其中<id>是顶级posts目录下的 markdown 文件的名称。
    • 既然我们有ssg-ssr.mdand pre-rendering.md,我们希望路径是/posts/ssg-ssrand /posts/pre-rendering

    步骤概述

    我们可以通过以下步骤来做到这一点。您不必进行这些更改- 我们将在下一页完成所有操作。

    首先,我们将创建一个名为**[id].js**under的页面pages/posts。以开头[和结尾的页面]是Next.js中的动态路由。

    pages/posts/[id].js中,我们将编写代码来呈现一个帖子页面——就像我们创建的其他页面一样。

    import Layout from '../../components/layout';
    
    export default function Post() {
      return <Layout>...</Layout>;
    }
    

    现在,这是新功能:我们将导出getStaticPaths从此页面调用的异步函数。在这个函数中,我们需要返回一个可能值的列表id

    import Layout from '../../components/layout';
    
    export default function Post() {
      return <Layout>...</Layout>;
    }
    
    export async function getStaticPaths() {
      // Return a list of possible value for id
    }
    

    最后,我们需要getStaticProps再次实现——这一次,使用给定的id. getStaticPropsis given params,其中包含id(因为文件名是[id].js)。

    import Layout from '../../components/layout';
    
    export default function Post() {
      return <Layout>...</Layout>;
    }
    
    export async function getStaticPaths() {
      // Return a list of possible value for id
    }
    
    export async function getStaticProps({ params }) {
      // Fetch necessary data for the blog post using params.id
    }
    

    这是我们刚刚讨论的内容的图形摘要:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1F5dAGgz-1653549168981)(images/how-to-dynamic-routes.png)]

    实现 getStaticPaths

    首先,让我们设置文件:

    • **[id].js**在目录中创建一个名为的pages/posts文件。
    • 另外,在目录中删除first-post.jspages/posts——我们将不再使用它。

    然后,pages/posts/[id].js在您的编辑器中打开并粘贴以下代码。我们稍后会填写...

    import Layout from '../../components/layout';
    
    export default function Post() {
      return <Layout>...</Layout>;
    }
    

    然后,打开并在底部lib/posts.js添加以下功能。getAllPostIds它将返回目录中的文件名列表(不包括.mdposts

    export function getAllPostIds() {
      const fileNames = fs.readdirSync(postsDirectory);
    
      // Returns an array that looks like this:
      // [
      //   {
      //     params: {
      //       id: 'ssg-ssr'
      //     }
      //   },
      //   {
      //     params: {
      //       id: 'pre-rendering'
      //     }
      //   }
      // ]
      return fileNames.map((fileName) => {
        return {
          params: {
            id: fileName.replace(/\.md$/, ''),
          },
        };
      });
    }
    

    重要提示:返回的列表不仅仅是一个字符串数组——它必须是一个看起来像上面注释的对象数组。每个对象都必须有params密钥并包含一个带有id密钥的对象(因为我们[id]在文件名中使用)。否则,getStaticPaths将失败。

    最后,我们将导入该getAllPostIds函数并在内部使用它getStaticPaths。在导出的组件上方打开pages/posts/[id].js并复制以下代码:Post

    import { getAllPostIds } from '../../lib/posts';
    
    export async function getStaticPaths() {
      const paths = getAllPostIds();
      return {
        paths,
        fallback: false,
      };
    }
    

    实现 getStaticProps

    我们需要获取必要的数据以使用给定的id.

    为此,请再次打开并在底部lib/posts.js添加以下功能。getPostData它将基于以下内容返回帖子数据id

    export function getPostData(id) {
      const fullPath = path.join(postsDirectory, `${id}.md`);
      const fileContents = fs.readFileSync(fullPath, 'utf8');
    
      // Use gray-matter to parse the post metadata section
      const matterResult = matter(fileContents);
    
      // Combine the data with the id
      return {
        id,
        ...matterResult.data,
      };
    }
    

    然后,打开pages/posts/[id].js并替换这一行:

    import { getAllPostIds } from '../../lib/posts';
    

    使用以下代码:

    import { getAllPostIds, getPostData } from '../../lib/posts';
    
    export async function getStaticProps({ params }) {
      const postData = getPostData(params.id);
      return {
        props: {
          postData,
        },
      };
    }
    

    帖子页面现在使用getPostData函数 ingetStaticProps来获取帖子数据并将其作为道具返回。

    现在,让我们更新Post要使用的组件postData。用以下代码pages/posts/[id].js替换导出的组件:Post

    export default function Post({ postData }) {
      return (
        <Layout>
          {postData.title}
          <br />
          {postData.id}
          <br />
          {postData.date}
        </Layout>
      );
    }
    

    就是这样!尝试访问这些页面:

    您应该能够看到每个页面的博客数据:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-t2qmaiSH-1653549168981)(images/image-20220525105444368.png)]

    渲染降价

    为了呈现 markdown 内容,我们将使用该remark库。首先,让我们安装它:

    npm install remark remark-html
    

    然后,打开lib/posts.js并将以下导入添加到文件顶部:

    import { remark } from 'remark';
    import html from 'remark-html';
    

    并按如下方式更新getPostData()同一文件中的函数以使用remark

    export async function getPostData(id) {
      const fullPath = path.join(postsDirectory, `${id}.md`);
      const fileContents = fs.readFileSync(fullPath, 'utf8');
    
      // Use gray-matter to parse the post metadata section
      const matterResult = matter(fileContents);
    
      // Use remark to convert markdown into HTML string
      const processedContent = await remark()
        .use(html)
        .process(matterResult.content);
      const contentHtml = processedContent.toString();
    
      // Combine the data with the id and contentHtml
      return {
        id,
        contentHtml,
        ...matterResult.data,
      };
    }
    

    重要提示:我们添加了**async**关键字 togetPostData是因为我们需要使用awaitfor remarkasync/允许您异步await获取数据。

    这意味着我们需要在调用时更新getStaticPropsinpages/posts/[id].js才能使用:await``getPostData

    export async function getStaticProps({ params }) {
      // Add the "await" keyword like this:
      const postData = await getPostData(params.id);
      // ...
    }
    

    最后,更新Post组件pages/posts/[id].jscontentHtml使用dangerouslySetInnerHTML

    export default function Post({ postData }) {
      return (
        <Layout>
          {postData.title}
          <br />
          {postData.id}
          <br />
          {postData.date}
          <br />
          <div dangerouslySetInnerHTML={{ __html: postData.contentHtml }} />
        </Layout>
      );
    }
    

    再次尝试访问这些页面:

    您现在应该可以看到博客内容:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jHoAo8Yf-1653549168982)(images/image-20220525112109950.png)]

    打磨帖子页面

    添加title到帖子页面

    pages/posts/[id].js中,让我们title使用帖子数据添加标签。您需要next/head在文件顶部添加一个导入,并title通过更新组件来添加标签Post

    // Add this import
    import Head from 'next/head';
    
    export default function Post({ postData }) {
      return (
        <Layout>
          {/* Add this <Head> tag */}
          <Head>
            <title>{postData.title}</title>
          </Head>
    
          {/* Keep the existing code here */}
        </Layout>
      );
    }
    
    格式化日期

    要格式化日期,我们将使用date-fns库。首先,安装它:

    npm install date-fns
    

    接下来,创建一个名为components/date.js并添加以下Date组件的文件:

    import { parseISO, format } from 'date-fns';
    
    export default function Date({ dateString }) {
      const date = parseISO(dateString);
      return <time dateTime={dateString}>{format(date, 'LLLL d, yyyy')}</time>;
    }
    

    注意:您可以在date-fns网站上查看不同的format()字符串选项。

    现在,打开,在文件顶部为组件pages/posts/[id].js添加一个导入,然后使用它:Date``{postData.date}

    // Add this import
    import Date from '../../components/date';
    
    export default function Post({ postData }) {
      return (
        <Layout>
          {/* Keep the existing code here */}
    
          {/* Replace {postData.date} with this */}
          <Date dateString={postData.date} />
    
          {/* Keep the existing code here */}
        </Layout>
      );
    }
    

    如果您访问http://localhost:3000/posts/pre-rendering,您现在应该会看到日期写为**“2020 年 1 月 1 日”**。

    添加 CSS

    最后,让我们使用之前添加的文件添加一些 CSS styles/utils.module.css。打开pages/posts/[id].js,然后为 CSS 文件添加导入,并将Post组件替换为以下代码:

    // Add this import at the top of the file
    import utilStyles from '../../styles/utils.module.css';
    
    export default function Post({ postData }) {
      return (
        <Layout>
          <Head>
            <title>{postData.title}</title>
          </Head>
          <article>
            <h1 className={utilStyles.headingXl}>{postData.title}</h1>
            <div className={utilStyles.lightText}>
              <Date dateString={postData.date} />
            </div>
            <div dangerouslySetInnerHTML={{ __html: postData.contentHtml }} />
          </article>
        </Layout>
      );
    }
    

    如果您访问http://localhost:3000/posts/pre-rendering,页面现在应该看起来更好一点:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9rS02ySZ-1653549168982)(images/image-20220525155306312.png)]

    润色索引页

    接下来,让我们更新我们的索引页面 ( pages/index.js)。我们需要使用该Link组件为每个帖子页面添加链接。

    打开pages/index.js并在文件顶部为 and 添加以下Link导入Date

    import Link from 'next/link';
    import Date from '../components/date';
    

    Home然后,在同一文件中组件的底部附近,将li标记替换为以下内容:

    <li className={utilStyles.listItem} key={id}>
      <Link href={`/posts/${id}`}>
        <a>{title}</a>
      </Link>
      <br />
      <small className={utilStyles.lightText}>
        <Date dateString={date} />
      </small>
    </li>
    

    如果你去http://localhost:3000,页面现在有每篇文章的链接:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4VBSAht3-1653549168983)(images/image-20220525160057266.png)]

    如果某些东西不起作用,请确保您的代码看起来像这样

    动态路线详情

    以下是您应该了解的有关动态路由的一些基本信息。

    获取外部 API 或查询数据库

    Like getStaticPropsgetStaticPaths可以从任何数据源获取数据。在我们的示例中,getAllPostIds(由 使用getStaticPaths)可以从外部 API 端点获取:

    export async function getAllPostIds() {
      // Instead of the file system,
      // fetch post data from an external API endpoint
      const res = await fetch('..');
      const posts = await res.json();
      return posts.map((post) => {
        return {
          params: {
            id: post.id,
          },
        };
      });
    }
    

    开发与生产

    倒退

    回想一下我们fallback: falsegetStaticPaths. 这是什么意思?

    如果fallbackfalse,则任何未返回的路径getStaticPaths都将导致404 页面

    如果fallbacktrue,则行为getStaticProps变化:

    • 从返回的路径getStaticPaths将在构建时呈现为 HTML。
    • 在构建时尚未生成的路径不会导致 404 页面。相反,Next.js 将在对此类路径的第一次请求时提供页面的“回退”版本。
    • 在后台,Next.js 会静态生成请求的路径。对同一路径的后续请求将为生成的页面提供服务,就像在构建时预渲染的其他页面一样。

    如果fallbackblocking,那么新路径将在服务器端呈现getStaticProps,并缓存以供将来的请求使用,因此每个路径仅发生一次。

    这超出了我们课程的范围,但您可以在文档fallback: true中了解更多信息。fallback: 'blocking'fallback

    包罗万象的路线

    ...通过在括号内添加三个点 ( ) 可以扩展动态路由以捕获所有路径。例如:

    • pages/posts/[...id].js匹配/posts/a, 但也/posts/a/b,/posts/a/b/c等等。

    如果你这样做, in getStaticPaths,你必须返回一个数组作为id键的值,如下所示:

    return [
      {
        params: {
          // Statically Generates /posts/a/b/c
          id: ['a', 'b', 'c'],
        },
      },
      //...
    ];
    

    并且params.id将是一个数组getStaticProps

    export async function getStaticProps({ params }) {
      // params.id will be like ['a', 'b', 'c']
    }
    

    查看catch all routes 文档以了解更多信息。

    路由器

    如果你想访问 Next.js 路由器,你可以通过useRouternext/router.

    404页

    要创建自定义 404 页面,请创建pages/404.js. 该文件是在构建时静态生成的。

    // pages/404.js
    export default function Custom404() {
      return <h1>404 - Page Not Found</h1>;
    }
    

    查看我们的错误页面文档以了解更多信息。

    更多示例

    我们已经创建了几个示例来说明getStaticProps并且getStaticPaths- 查看它们的源代码以了解更多信息:

    API路由

    创建 API 路由

    API 路由允许您在 Next.js 应用程序中创建 API 端点。您可以通过在具有以下格式的目录中创建一个函数来做到这一点:pages/api

    // req = HTTP incoming message, res = HTTP server response
    export default function handler(req, res) {
      // ...
    }
    

    在API Routes 文档中了解有关上述请求处理程序的更多信息。

    它们可以部署为无服务器函数(也称为 Lambda)。

    创建一个简单的 API 端点

    让我们试试看。创建一个使用以下代码调用hello.js的文件:pages/api

    export default function handler(req, res) {
      res.status(200).json({ text: 'Hello' });
    }
    

    尝试在http://localhost:3000/api/hello访问它。你应该看到{"text":"Hello"}。注意:

    就是这样!在结束本课之前,让我们在下一页讨论使用API 路由的一些技巧。

    API路由详情

    以下是您应该了解的有关API 路由的一些基本信息。

    不要从getStaticProps或获取 API 路由getStaticPaths

    您不应getStaticProps或获取 API 路由getStaticPathsgetStaticProps相反,直接在or中编写服务器端代码getStaticPaths(或调用辅助函数)。

    原因如下:getStaticProps并且getStaticPaths只在服务器端运行,永远不会在客户端运行。此外,这些功能不会包含在浏览器的 JS 包中。这意味着您可以编写诸如直接数据库查询之类的代码,而无需将它们发送到浏览器。阅读编写服务器端代码文档以了解更多信息。

    一个好的用例:处理表单输入

    API 路由的一个很好的用例是处理表单输入。例如,您可以在页面上创建一个表单并让它向POST您的 API 路由发送请求。然后,您可以编写代码将其直接保存到数据库中。API Route 代码不会包含在您的客户端包中,因此您可以安全地编写服务器端代码。

    export default function handler(req, res) {
      const email = req.body.email;
      // Then save email to your database, etc...
    }
    

    预览模式

    当您的页面从无头 CMS 获取数据时,静态生成非常有用。但是,当您在无头 CMS 上编写草稿并希望立即在页面上预览草稿时,这并不理想。您希望 Next.js 在请求时而不是构建时呈现这些页面,并获取草稿内容而不是发布的内容。您希望 Next.js 仅针对这种特定情况绕过静态生成。

    Next.js 有一个名为Preview Mode的功能来解决上述问题,它利用API Routes。要了解有关它的更多信息,请查看我们的预览模式文档。

    动态 API 路由

    API 路由可以是动态的,就像常规页面一样。查看我们的动态 API 路由文档以了解更多信息。

    更多相关内容
  • Next.js API路由的中间件 Next.js发布了版本9,该版本添加了API路由。 这使我们能够编写API。 当前,Next.js发行了版本10,但是,我认为...仍然缺少一些东西:中间件。 因为正式的Next.js文档建议在编写函数,所以...
  • 5美元的技术解锁2021年! 5美元的竞选活动从2020年12月15日至2021年1月13日。 真实的Next.js 真实世界Next.js,由Packt发布
  • 完美的入门工具包,可使用Next.js和Notion构建漂亮的网站。 Next.js Notion入门工具包完美的入门工具包,可用于通过Next.js和Notion构建漂亮的网站。 简介此仓库是我用来为我的个人博客/投资组合网站transivebullsh....
  • 使next.js的页面转换更容易|让next.js的页面切换动画更简单 快速浏览 用法使用方法 组件/wrapper.js import w from 'next-page-transition' import { zoomfade } from 'next-page-transition/dist/presets' export...
  • Next-Express.jsNext.js + Express.js变得简单 是一个使用Node.js和React轻松创建Web应用程序的框架。 它提供了用于样式,路由,处理服务器端处理等的内置解决方案。 对于复杂的网站,您通常希望将其与(通常使用...
  • 以声明的方式向您的Next.js项目添加持久和嵌套的布局。 安装 $ npm install @moxy/next-layout 该库是用现代JavaScript编写的,并以CommonJS和ES模块的编译变体形式发布。 如果您以较旧的浏览器为目标,请确保相应...
  • Next.js API路由是将后端功能添加到React应用程序的一种非常有趣且简单的方法。 但是,当需要添加中间件时,没有简单的方法来实现它。 Next.js API中间件简介Next.js API路由是将后端功能添加到React应用程序的一种...
  • Next.js +图片 在导入图像(默认情况下为jpg,jpeg,png,svg,fig,ico,webp,jp2和avif图像)。 特征 从本地计算机加载图像 从远程(例如CDN)加载图像 将小型图像内联到Base64以减少http请求 在文件名中添加...
  • Next.js模板 这基于 Next.js示例项目。 引导开发人员友好的NextJS应用程序,该应用程序配置为:用用格式默认情况下使用进行提交挂钩的类型检查,类型检查和格式化使用和 Testing 它还包括我的,使您可以轻松地开始该...
  • 下次认证 Next.js的身份验证和授权next-authentication提供了一组功能和中间件,以在Next.js应用程序中实现身份验证,授权和会话管理。用法建立: // Setup// file: lib/auth.jsimport bcrypt from 'bcrypt' ;import...
  • 下一个网站 ... 对于构建静态以及组合的静态和单页应用程序(SPA),Next.js会更轻松,更灵活。 目标 使用编写的内容构建一个静态站点。 内容已存储并在GitHub存储库中可读。 没有服务器的100%静态输
  • 本示例说明如何在Next.js应用程序中使用 。 它使用getInitialProps从HTTP端点获取旧消息,就好像它是Rest API一样。 该示例将WebSocket服务器与Next服务器结合在一起,在生产应用程序中,您应该将它们拆分为不同的...
  • 本书涵盖以下激动人心的功能: 探索使用Next.js进行服务器端渲染的好处通过了解代码拆分和绑定,将JavaScript模块创建并链接在一起创建网站页面并通过网站导航将它们链接在一起使用其他Webpack加载程序和功能以及...
  • Next.js + Express 使用Spotify API的Next.js项目( )。构建设置# Dependencies$ npm install# Serve at at localhost:3000$ npm run dev文件
  • 下一个存储提供商 Next.JS 插件,用于使用 Redis 和 Amazon S3 等 API 存储和缓存 ISR 呈现的页面 :red_exclamation_mark: 使用前重要 :red_exclamation_mark: 当前不支持在 Next.JS 中使用自定义存储提供程序(并且...
  • Next.js中CSS + LESS + SASS +模块 描述 该模块允许您在一个软件包中一起使用css(+可选的[less,sass,模块])。 它使用可用的最新模块css-loader,less-loader,sass-loader,postcss。 检查出源,它的死法很简单...
  • 下一个记录者Next.js 的 JSON 日志修补程序描述这是一个用于修补使用的日志功能的,将它们作为换行符分隔的 JSON 输出到stdout 。 这允许 Next.js 应用程序以与日志聚合器兼容的格式记录服务事件,而无需自定义 Next...
  • 这是一个用引导的项目。 入门 首先,运行开发服务器: npm run dev # or yarn dev 用浏览器打开以查看结果。...部署Next.js应用程序的最简单方法是使用Next.js创建者提供的。 请查看我们的以获取更多详细信息。
  • Next.js缓存清除 介绍 在页面中使用getStaticProps时,Next.js通过将其预呈现为静态HTML来进行。 对于具有使用getStaticPaths预定义路由器的静态或静态生成的页面(在构建时),具有增量静态生成的页面(在首次请求...
  • 用于Next.js的Nest模块 将与服务器一起使用。 为什么? 允许您在单个存储库中同时管理前端和后端。 并且您维护一个域example.com而不是两个: example.com和api.example.com 。 安装 yarn add @nest-module/next ...
  • 基本用法您的_app.js 。 import { I18nProvider } from 'next-localization' ;import { useRouter } from 'next/router' ;export default function MyApp ( { Component , pageProps } ) { const r
  • Micro Frontend Fun(不费吹灰之力) 该项目是您的下一个微型前端项目的模板。 用法示例: 模板的用法 ...搭建微碎片的样板 FUN_FRAGMENT_NAME=Header FUN_PORT=3000 ./copy.sh header FUN_FRAGMENT_NAME=Footer FUN...
  • :star-struck: 该软件包使您可以在类似Next.js的隔离上下文中快速测试Next.js API路由/处理程序。 next-test-api-route-handler (NTARH)使用Next.js的内部API解析器精确模拟API路由处理。 为了保证稳定性,将针对...
  • Next.js的cookie助手集合 产品特点 :sparkles: SSR支持,用于设置器,解析器和销毁 :gear: 自定义Express服务器支持 :feather:超轻 :shield: 完美的身份验证 设置和销毁cookie也可以在服务器端进行。 快速开始 ...
  • Next.js :red_heart: MongoDB) :plus: Passport.js 使用 , 和构建的身份验证应用 :rainbow: 放一个 :star: 如果你喜欢 特征 :check_mark: 没有Express.js :check_mark: 无服务器就绪 :check_mark: API路由 :...
  • Next.js插件可使用Babel编译所有node_modules 。 动机 程序包作者应将任何JavaScript代码发布到npm,只要它只是纯有效JavaScript(任何版本)即可。 在软件包级别进行编译是没有意义的,因为作者不知道在哪种上下文...
  • next-routes, Next.js的通用动态路由 Next.js 动态路由 易于使用通用动态路由的Next.js表达式和参数匹配面向 express &的请求处理程序中间件通过路由定义生成url的Link 和 Router:如何使用安装:npm
  • 安装$ npm install @moxy/next-router-scroll 该库是用现代JavaScript编写的,并以CommonJS和ES模块的已编译变体形式发布。 如果您以较旧的浏览器为目标,请确保相应地进行翻译。动机在某些情况下,您需要控制如何...
  • Next.js的模块联合 该插件在Next.js上启用模块联合 这是解决由于Next.js同步而导致的硬限制的解决方法。 我正在对Webpack Core进行更新,它将绕过具有较旧体系结构(如Next.js)的项目。 在解决利用模块联合的稳定...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 409,532
精华内容 163,812
关键字:

next.js

友情链接: CGLoader2.9.rar