域名 AXUM.RS 将于2025年10月到期。我们无意再对其进行续费,我们希望你能够接续这个域名,让更多 AXUM 开发者继续受益。
  • 方案1️⃣AXUM.RS 域名 = 3000
  • 方案2️⃣方案1️⃣ + 本站所有专题原始 Markdown 文档 = 5000
  • 方案3️⃣方案2️⃣ + 本站原始数据库 = 5500
如果你有意接续这份 AXUM 情怀,请与我们取得联系。
说明:
  1. 如果有人购买 AXUM.RS 域名(方案1️⃣),或者该域名到期,本站将启用新的免费域名继续提供服务。
  2. 如果有人购买了 AXUM.RS 域名,且同时购买了内容和/或数据库(方案2️⃣/方案3️⃣),本站将关闭。届时我们或许会以另一种方式与你再相遇。

组件与渲染

本章讨论新版 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 组件,我们通过 useStateuseEffect 来实现:

"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/组件与渲染分支。

要查看完整内容,请先登录