首页
Preview

Next.js14(App Router)基础知识

前言

在开始项目之前,我们需要了解什么是CSRSSR? 为什么我们要学习Next.js?

为什么要学习Next.js

  1. React生态系统:Next.js是建立在React之上的,它提供了许多增强的功能和工具,使得开发React应用程序更加容易和高效。

  2. 服务器渲染(SSR):Next.js支持服务器渲染,这意味着你可以在服务器上预渲染页面,然后将其发送到客户端。这可以提高页面的加载速度和搜索引擎优化(SEO)。

  3. 静态网站生成(SSG):Next.js还支持静态网站生成,这意味着你可以在构建时预渲染整个网站,并将其作为静态文件部署。这可以提高网站的性能和安全性。

  4. 路由和导航:Next.js提供了强大的路由和导航功能,使你能够轻松地管理应用程序的不同页面和导航。

  5. 数据获取:Next.js提供了多种数据获取方法,包括从API获取数据和从数据库获取数据。这使得与后端集成变得更加容易。

  6. 插件和扩展性:Next.js具有丰富的插件生态系统,可以轻松地扩展和定制的应用程序。

CSR(客户端渲染)

是一种网页开发技术,其中网页内容的渲染主要由用户的网络浏览器(客户端)而不是服务器执行。在客户端渲染中,Web服务器通常向客户端发送原始数据或最小的HTML框架,然后在客户端的浏览器中运行的JavaScript获取额外的数据并动态呈现最终的网页。因此,用户在所有过程完成之前无法看到任何内容。

优点

  • 减少了服务器请求页面的次数
  • 快速交互(因为它一次性加载所有页面)
  • 页面切换时没有闪烁

缺点

  • SEO差(搜索引擎优化)
  • 初始加载速度慢(因为它一次性加载所有页面)
  • 首次访问后加载速度快(因为所有页面都已缓存)

SSR(服务器端渲染)

是一种网页开发技术,其中Web服务器在用户请求页面时生成网页的HTML内容,并将完全渲染的HTML发送到客户端的网络浏览器。因此,用户可以在进程进行中看到服务器上预渲染的HTML界面。

优点

  • 良好的SEO(因为页面在服务器上完全呈现,搜索引擎可以轻松爬取和索引内容)
  • 初始加载速度快(因为它只加载特定页面)

缺点

  • 频繁的服务器请求页面创建
  • 交互速度较慢
  • 页面切换时有闪烁效果

创建 Next.js项目

  • 安装
npx create-next-app@latest my-project
  • 偏好选项配置

√ TypeScript(Yes)

√ ESLint (Yes)

√ Tailwind CSS(Yes)

src/?(No)

√ App Router(推荐)(Yes)

√ 您想自定义默认导入别名吗?(Yes)

  • 运行
npm run dev
  • 浏览

http://localhost:3000

Next.js 14版本中的新功能

app目录

在之前的Next.js版本中,所有页面都应该生成在pages目录中(页面路由器)。对于新应用程序,Next.js团队建议使用App Router(应用路由器)。这个路由器允许开发者使用React的最新功能,并且是基于社区反馈的先前版本的演变。

Streaming and Suspense (流式)

另一个功能是使用页面中的Suspense边界将内容流式传输到浏览器。例如,页面的某个部分正在从服务器获取数据。不要为整个页面显示加载消息,而是提供其余页面,并且只在包含获取数据的特定部分显示加载消息,同时,其余页面不受包含获取数据的部分的影响。

客户端组件和服务器组件

有两种创建组件的方式。

  1. 客户端组件
  • 添加use client,声明是客户端组件
  • 在服务器上渲染并在浏览器中进行Hydrated(水合作用)
  • 使用场景,如果组件包含交互操作(例如useState,useEffect,onClick,onChange ...)
  1. 服务器组件
  • 默认是服务器组件(无需声明)
  • 在服务器上呈现,无需Hydrated(水合)
  • 使用场景,组件不包含任何交互操作

建议尽可能多的使用服务器组件,如果应该使用客户端组件,建议单独创建客户端组件,然后导入他。

什么是Hydration(水合作用)

将交互功能添加到预渲染的HTML的过程。

路由

在之前的Next.js版本中,文件名用于路由。

/news => news.tsx 

在13版本中,创建包含页面的目录和文件

/news => news/page.tsx

如果有嵌套路由,

/news/latest => news/latest/page.tsx
app
├── news
│     ├── latest
│     │      └── page.tsx (/news/latest)
│     └── page.tsx (/news)

布局

而在App Router中,直接保存在app目录下的layoutx.tsx文件会应用于所有page.tsx文件。layout.tsx是根布局文件,是必须的,根布局必须定义<html><body>标签,因为 Next.js 不会自动创建它们。

根布局默认是服务器组件,不能设置为客户端组件。

链接(Link)

要使用Link组件,需要导入next/link

import Link from "next/link";

导航(Navigation)

Next.js提供了有用的导航功能(useRouter,notFound…) 使用useRouter()我们可以写编程式导航,但是它只能在客户端组件内使用。

import { useRouter } from 'next/navigation'

图片(Image)

使用Next.js的<Image>而不是<img>,要使用必须要引入。

import Image from 'next/image'

loading和error和not-found

在ReactJS中,为了反映页面的加载或错误,我们需要创建每个状态并更改状态以进行重新渲染。此外,如果用户访问未指定的路由,我们需要在路由处理中使用'*'设置404页面路由。

在Next.js中,我们可以在不设置状态或路由的情况下显示每个页面。我们只需要创建一个名为(loading和error和not-found)的文件。(当然,我们可以像在ReactJS中那样设置状态,但是应该为客户端组件声明'use client')

  • loading.tsx(或loading.jsx) 当api调用正在处理或页面正在加载时,将自动呈现此文件。

  • error.tsx(或error.jsx) 当发生错误时,将自动呈现此文件。

  • not-found.tsx(或not-found.jsx) 当返回notFound()或访问未指定的路由时,将呈现此文件。

import { notFound } from 'next/navigation';
// ...
if (!condition) return notFound();

动态路由

  • 动态参数 可以通过将文件夹的名称用方括号括起来来创建动态段:[folderName]。例如,[id] [slug]
app
├── news
│     ├── [id]
│     │     └── page.tsx (/news/1 或者 /news/2)

它是通过props传递的。因此,我们可以通过props.params.id获取参数数据('id'是你在路由目录名称中指定的名称)。

  • 设置静态参数

所以每当我们点击一条新闻,就可以通过动态路由来处理,然而,每次都要获取所选新闻数据并进行服务器端渲染。那么这些都是需要时间来处理的。在这一点上,我们可以使用generateStaticParams,用静态参数替换处理动态参数。

我们需要在文件中创建generateStaticParams函数。并调用API来接收所有新闻ID,并将它们作为props发送到组件,以下是示例代码。

const News = async ({ params }: { params: { id: string }}) => {
  return (
    <section>
      <div>News Detail</div>

      <Suspense fallback={<Loading />}>
        <NewsDetail id={params.id} />
      </Suspense>
    </section>
  );
};

export default News;

export async function generateStaticParams() {
  const news: INews[] = await getAllNewsAPI(); //获取所有新闻数据
  return news.map((news: INews) => {
    return { id: news.id.toString() }; // 匹配
  });
}

我们可以在构建的时候检查,是否是静态的。

  • 对于动态参数,此页面将是
λ /news/[id]

这意味着每当请求到来时都会生成页面(也实现API调用)

  • 对于静态参数,此页面将是
● /news/[id]

/news/1,/news/2…

这意味着当请求到来时不会生成页面(也不会实现API调用)。

API

Next.js提供了构建公共API的解决方案。在解释公共API之前,我想分享一些处理外部获取数据的概念。

  • force-cache

如果我们发送用于获取数据的请求,响应的数据将被缓存。这些缓存的数据将保留,直到手动失效。类似于Next.js 12中的getStaticProps(SSG - 静态站点生成)。force-cache是默认值,可以省略。它可用于不经常更改的数据。

fetch('URL', { cache: 'force-cache' });
  • no-store

如果我们发送用于获取数据的请求,响应的数据应该在每个请求上重新获取。类似于Next.js 12中的getServerSideProps(SSR - 服务器端渲染)。它可用于频繁更改的数据。

fetch('URL', { cache: 'no-store' });
  • Revalidate

如果我们使用force-cache进行请求,数据将被缓存。如果响应数据发生更改怎么办?然后,我们应该重新构建应用程序并再次部署。为了避免这项工作,作为替代,我们可以使用Revalidate选项。该请求应该被缓存一段时间,并在一段时间后重新验证。类似于Next.js 12中具有revalidate选项的getStaticProps(ISR - 增量静态再生)。

fetch('URL', { next: { revalidate: 30 } });
// 数据将被缓存30秒。
// 30秒后,将在后台重新获取。
// 后台意味着,如果您在30秒后刷新页面,数据不会更改,但后台的真实数据会被重新获取。
// 如果再次刷新,将呈现新的重新获取的数据。

API目录和路由文件

在应用程序目录中,可以在api目录中处理所有的API。在api目录中,您可以设置路由名称目录。最后,为配置创建route.tsroute.js文件(设置GET / POST / PUT / DELETE方法)。

app
├── api
│    ├── news
│    │    └── route.ts (/api/news)
  • GET
import { NextResponse } from "next/server";

// http://localhost:3000/api/news (GET)
export async function GET() {
 
  return NextResponse.json({ ... });
};

// http://localhost:3000/api/news?title=sports&published=today (GET)
export async function GET(request: Request) {
  const { searchParams } = new URL(request.url);
  const title = searchParams.get('title');
  const published = searchParams.get('published');
  
  return NextResponse.json({ ... });
};
  • POST
import { NextResponse } from "next/server";

// http://localhost:3000/api/news (POST)
export async function POST(request: Request) {
  const { title, published }: Partial<INews> = await request.json();
  if(!title || !published) return NextResponse.json({ message: '没有数据' });
  
  return NextResponse.json({ ... });
};
  • PUT
import { NextResponse } from "next/server";

// http://localhost:3000/api/news (PUT)
export async function PUT(request: Request) {
  const { title, published }: Partial<INews> = await request.json();
  if(!title || !published) return NextResponse.json({ message: '没有数据' });
 
  return NextResponse.json({ ... });
};
  • DELETE
import { NextResponse } from "next/server";

// http://localhost:3000/api/news (DELETE)
export async function DELETE(request: Request) {
  const { id }: Partial<INews> = await request.json();
  if(!id) return NextResponse.json({ message: '没有数据' });
  return NextResponse.json({ ... });
};

版权声明:本文内容由TeHub注册用户自发贡献,版权归原作者所有,TeHub社区不拥有其著作权,亦不承担相应法律责任。 如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

点赞(0)
收藏(0)
夏天的猫
一个人的生命是应该这样度过的:当他回首往事的时候,不因虚度年华而悔恨,也不因碌碌无为而羞耻。

评论(0)

添加评论