约定即配置
本章我们来看一下 `create-next-app` 的选项、目录结构以及 Next.js 的「约定即配置」。定义路由
本章将讨论 Next.js 定义路由的方式,包括:普通路由、动态路由、嵌套路由及嵌套动态路由。布局
本章讨论 Next.js App 路由的布局。相比之前的 Pages 路由,App 路由的布局简单多了:Next.js 会自动调用布局文件。组件与渲染
本章讨论新版 Next.js 中变化最大的部分:组件和渲染。“正在载入”的实现
Next.js 的 App 路由有一个约定:定义 `loading.js`,那么 Next.js 会自动在页面加载中显示这个组件,加载完成之后,自动隐藏该组件。错误处理
本章将讨论 Next.js 的错误处理。
组件与渲染
本章讨论新版 Next.js 中变化最大的部分:组件和渲染。
和之前版本相比,Next.js 最大的变化就是:所有组件默认都是服务端组件,相应地,它们使用的就是服务端渲染。
- 不太严谨地说:除非你使用了
getServerSideProps()
,否则可以视为客户端组件和客户端渲染(当然还可能是其它渲染,通过getXXProps()
) - 可以在组件中直接使用 React 的
useState()
、useEffect()
等 hook
服务端组件
现在 Next.js 默认所有组件都是服务端组件:
- 需要使用
"use client"
语句声明该组件是客户端组件 - 可以使用 React 的
useState()
、useEffect()
等 hook - Next.js 的约定中,有一些是必须是客户端组件
我们分别编写服务端组件和客户端组件来通过https://httpbin.org/ip来获取IP。
客户端组件
先从我们熟悉的客户端组件开始。客户端组件其实就是传统的 React 组件,我们通过 useState
和 useEffect
来实现:
"use client";
import React, { useEffect, useState } from "react";
export default function IPClient() {
const [ip, setIp] = useState("正在获取");
useEffect(() => {
fetch("https://httpbin.org/ip")
.then((res) => res.json())
.then((data) => {
setIp(data.origin);
})
.catch((e) => {
console.log(e);
setIp(`获取失败,请重试`);
});
}, []);
return <div>客户端组件获取到的IP:{ip}</div>;
}
"use client";
:告诉 Next.js ,这是一个客户端组件- 使用
useState()
来维护ip数据 - 在
useEffect()
中,通过fetch()
从远程API中获取数据 - 客户端组件中的
fetch()
是由浏览器提供的
服务端组件
export default async function IPServer() {
let ip = "正在获取";
try {
const res = await fetch("https://httpbin.org/ip");
const data = await res.json();
ip = data.origin;
} catch (e) {
ip = "发生错误,请重试";
}
return <div>服务端组件获取到的IP:{ip}</div>;
}
- 无须特别声明,在 Next.js 所有组件默认都是服务端组件
- 可以使用
await
- 服务端组件中的
fetch()
是由 Next.js 提供的
入口文件
import { IPClient, IPServer } from "@/components/Ip";
import Link from "next/link";
export default function Home({ searchParams }) {
const isClientStr = searchParams.client || "";
const isClient = isClientStr === "1";
return (
<>
{isClient ? <IPClient /> : <IPServer />}
<div style={{ display: "flex", gap: "1rem" }}>
<Link href="/">服务端组件</Link>
<Link href="/?client=1">客户端组件</Link>
</div>
</>
);
}
本章代码位于03/组件与渲染分支。