React Server Components手把手教学(三)

本文涉及的产品
云数据库 MongoDB,通用型 2核4GB
云数据库 MongoDB,独享型 2核8GB
推荐场景:
构建全方位客户视图
简介: React Server Components手把手教学(三)

服务器组件与客户端代码完全兼容

服务器组件与客户端代码完全兼容,这意味着客户端组件和服务器组件可以在同一个 React 树中进行渲染。通过将大部分应用程序代码移到服务器上,服务器组件有助于防止客户端数据获取的瀑布效应,快速解决服务器端的数据依赖关系。

在传统的客户端渲染中,组件使用 React Suspense“暂停”其渲染过程(并显示回退状态),同时等待异步工作完成。通过服务器组件,数据获取和渲染都在服务器上进行,因此 Suspense 也会在服务器端管理等待期,从而缩短总的往返时间,加快回退和完成页面的渲染。

需要注意的是,客户端组件在初始加载时仍然进行服务器端渲染(SSR)。服务器组件模型并不取代 SSR 或 Suspense,而是与它们一起工作,根据需要为用户提供应用程序的所有部分

image.png

在使用 Next.jsReact 服务器组件时,数据获取和 UI 渲染可以在同一个组件中完成。此外,服务器操作(Server Actions)为用户提供了在页面上的 JavaScript 加载之前与服务器端数据进行交互的方式。


9. 如何使用Next.js和MongoDB构建课程列表页面

现在让我们用Next.js构建一个使用RSC的应用程序。

因此,我们现在将构建一个课程列表页面,以展示我们如何在Next.js中创建服务器组件,以及它与客户端组件的不同之处。

请注意,我们不会在这里深入学习Next.jsMongoDB。我们只是将这个应用程序作为一个示例,来教我们RSC的工作原理以及它们与客户端组件的区别。

首先,让我们将课程数据添加到数据存储中。对于这个应用程序,我使用了MongoDB。下面的图像显示添加了三个课程的三个文档。

image.png

接下来,我们将创建一个实用函数来建立与MongoDB的连接。这是一个通用的代码,我们可以在任何基于JavaScript的项目中使用它,以使用MongooseMongoDB URI连接到MongoDB

import mongoose from "mongoose";
export async function dbConnect(): Promise<any> {
  try {
    const conn = await mongoose.connect(String(process.env.MONGO_DB_URI));
    console.log(`Database connected : ${conn.connection.host}`);
    return conn;
  } catch (err) {
    console.error(err);
  }
}

现在,我们需要创建与MongoDB文档相对应的模型(modal)。由于我们处理的是课程数据,这是与之对应的模型:

import mongoose, { Schema } from "mongoose";
const schema = new Schema({
  name: {
      required: true,
      type: String
  },
  description: {
      required: true,
      type: String
  },
  cover: {
    required: true,
    type: String
  },
  rating: {
    required: true,
    type: Number
  },
  price: {
    required: true,
    type: Number
  },
  createdOn: {
    type: { type: Date, default: Date.now }
  },
  link: {
    required: true,
    type: String
  },
  type: {
    required: true,
    type: String
  },
  comments: {
    required: false,
    type: [{ body: String, date: Date }]
  }
});
export const courses = mongoose.models.course ?? mongoose.model("course", schema);

通过Next.js App Router,所有的组件默认都是服务器组件。这意味着它们位于靠近服务器的位置,并且可以访问我们的服务器生态系统。

下面的代码是一个常规的Next.js组件,但具有一个特殊功能:我们可以在组件中直接获取数据库连接,并直接查询数据,而无需经过任何状态和效果管理

从该组件中记录的任何内容都不会被记录到我们的浏览器控制台,因为这是一个服务器组件。我们可以在服务器控制台中查看日志(我们可以使用yarn dev命令启动服务器的终端)。

由于与数据库的交互是异步的,我们在进行调用时使用await关键字,并在组件上使用async关键字。在接收到响应后,我们将其作为属性传递给子组件。

import { dbConnect } from '@/services/mongo'
import { courses } from '@/models/courseModel'
import { addCourseToDB } from './actions/add-course'
import AddCourse from './components/AddCourse'
import CourseList from './components/CourseList'
export default async function Home() {
  // 建立MongoDB链接
  await dbConnect();
  //获取所有的数据信息
  const allCourses = await courses.find().select(
              ["name", "cover", "rating"]);
  // 在服务器终端中打印显示数据
  console.log({allCourses})
  return (
    <main>
      <div>
        <h1>Courses</h1> 
        <AddCourse addCourseToDB={addCourseToDB} />
        <CourseList allCourses={allCourses} />  
      </div>
    </main>
  )
}

Home组件包含:

  • 一个标题
  • 一个组件(AddCourse),用于包装一个添加课程的按钮
  • 一个组件(CourseList),用于将课程显示为列表。

image.png

我们知道,服务器组件可以同时渲染客户端和服务器组件AddCourse组件需要用户交互,即用户需要点击按钮来添加课程。所以它不能是服务器组件.

因此,让我们为AddCourse创建一个客户端组件。通过Next.js App Router,默认情况下,所有组件都是服务器组件。

如果我们想创建一个客户端组件,我们必须在组件顶部(甚至在任何导入语句之前)使用名为use client的指令来明确创建一个客户端组件。

客户端组件- AddCourse

'use client'
import { useState } from 'react';
import Modal from './Modal';
import AddCourseForm from "./AddCourseForm";
export default function AddCourse({
  addCourseToDB,
}: {
  addCourseToDB: (data: any) => Promise<void>
}) {
  const [showAddModal, setShowAddModal] = useState(false);
  const add = async(data: any) => {
    await addCourseToDB(data);
    setShowAddModal(false);
  }
  return (
    <>
      <button
        onClick={() => setShowAddModal(true)}
      >
        Add Course
      </button>
      <Modal 
        shouldShow={showAddModal} 
        body={
          <AddCourseForm 
            saveAction={add} 
            cancelAction={() => setShowAddModal(false)} />} />
    </>
  )
}

服务器组件 -CourseList

CourseList组件不需要任何事件处理程序,因此我们可以将其保持为服务器组件。

import Image from 'next/image'
import Link from 'next/link'
export default function CourseList(courseList: any) {
  const allCourses = courseList.allCourses;
  return(
    <div>
      {
        allCourses.map((course: any) =>
        <Link key={course['_id']} href={`/courses/${course['_id']}`}>
          <div>
            <Image
              src={course.cover}
              width={200}
              height={200}
              alt={course.name}
            />
            <h2>{course.name}</h2>
            <p>{course.rating}</p>
          </div> 
        </Link> 
      )}
    </div>  
  )
}
我们打开浏览器开发工具的Sources选项卡,以确定客户端上下载了什么,服务器上留下了什么。我们在这里是看不到page.tsx文件或CourseList.tsx文件信息。这是因为这些是服务器组件,它们永远不会成为我们的客户端捆绑包的一部分

我们只会看到我们在应用程序中明确标记为客户端组件的组件。

image.png

Next.js App Router 中,所有获取的数据现在默认为静态数据,在构建时渲染。然而,这可以很容易地改变:Next.js 扩展了 fetch 选项对象,以提供缓存和重新验证规则的灵活性。

我们可以使用 {next: {revalidate: number}} 选项以设置的时间间隔或在后端更改发生时刷新静态数据(增量静态再生成),而 {cache: 'no-store'} 选项可以在动态数据的 fetch 请求中传递(服务器端渲染)。


总结

总结一下:

  • React服务器组件具有后端访问权限,无需进行任何网络往返。
  • 我们可以通过使用RSC来避免网络瀑布问题。
  • React服务器组件支持自动代码拆分,并通过零捆绑大小提高应用程序的性能。
  • 由于这些组件位于服务器端,它们无法访问客户端端的事件处理程序、状态和效果。这意味着我们不能使用任何事件处理程序或React钩子,如useStateuseReduceruseEffect
  • React服务器组件可以导入并渲染客户端组件,但反之则不成立。但我们可以将服务器组件作为props传递给客户端组件。
  • RSC并不意味着取代客户端组件。健康的应用程序同时使用服务器组件来进行动态数据获取以及客户端组件来实现丰富的交互性。挑战在于确定何时使用每种组件。

后记

分享是一种态度

参考资料:

  1. understanding-react-server-components
  2. react-server-components-for-beginners/
  3. how-to-use-react-server-components/
  4. what-even-are-react-server-components/

全文完,既然看到这里了,如果觉得不错,随手点个赞和“在看”吧。

相关实践学习
MongoDB数据库入门
MongoDB数据库入门实验。
快速掌握 MongoDB 数据库
本课程主要讲解MongoDB数据库的基本知识,包括MongoDB数据库的安装、配置、服务的启动、数据的CRUD操作函数使用、MongoDB索引的使用(唯一索引、地理索引、过期索引、全文索引等)、MapReduce操作实现、用户管理、Java对MongoDB的操作支持(基于2.x驱动与3.x驱动的完全讲解)。 通过学习此课程,读者将具备MongoDB数据库的开发能力,并且能够使用MongoDB进行项目开发。 &nbsp; 相关的阿里云产品:云数据库 MongoDB版 云数据库MongoDB版支持ReplicaSet和Sharding两种部署架构,具备安全审计,时间点备份等多项企业能力。在互联网、物联网、游戏、金融等领域被广泛采用。 云数据库MongoDB版(ApsaraDB for MongoDB)完全兼容MongoDB协议,基于飞天分布式系统和高可靠存储引擎,提供多节点高可用架构、弹性扩容、容灾、备份回滚、性能优化等解决方案。 产品详情: https://www.aliyun.com/product/mongodb
相关文章
|
6月前
|
Rust 前端开发 JavaScript
用Rust搭建React Server Components 的Web服务器(三)
用Rust搭建React Server Components 的Web服务器(三)
|
6月前
|
Rust 前端开发 JavaScript
用Rust搭建React Server Components 的Web服务器(二)
用Rust搭建React Server Components 的Web服务器(二)
|
6月前
|
Rust 前端开发 中间件
用Rust搭建React Server Components 的Web服务器(一)
用Rust搭建React Server Components 的Web服务器(一)
|
6月前
|
存储 前端开发 JavaScript
React Server Components手把手教学(二)
React Server Components手把手教学(二)
|
10月前
|
前端开发
前端学习笔记202305学习笔记第二十九天-React keep alive原理之2
前端学习笔记202305学习笔记第二十九天-React keep alive原理之2
46 0
|
10月前
|
前端开发
前端学习笔记202306学习笔记第四十八天-react-admin marmelab之8
前端学习笔记202306学习笔记第四十八天-react-admin marmelab之7
32 0
|
1月前
|
前端开发 JavaScript
前端知识笔记(二十六)———React如何像Vue一样将css和js写在同一文件
前端知识笔记(二十六)———React如何像Vue一样将css和js写在同一文件
37 1
|
7月前
|
前端开发
前端笔记:React的form表单全部置空或者某个操作框置空的做法
在React框架前端开发中,经常会有弹出框的开发,涉及到弹出框,难免就会有表单。一般在关闭弹出框或者对表单联动时,往往都需要考虑对表单进行置空操作了。
60 0
|
10月前
|
Web App开发 前端开发 JavaScript
前端学习笔记202307学习笔记第五十七天-模拟面试笔记react-fiber解决了什么问题
前端学习笔记202307学习笔记第五十七天-模拟面试笔记react-fiber解决了什么问题
54 0
|
10月前
|
JavaScript 前端开发 调度
前端学习笔记202307学习笔记第五十七天-模拟面试笔记react-fiber和虚拟dom关系
前端学习笔记202307学习笔记第五十七天-模拟面试笔记react-fiber和虚拟dom关系
86 0

热门文章

最新文章