React Server Components 简介

原文信息: 查看原文查看原文

React Server Components in a Nutshell

- Paul Scanlon

Paul Scanlon使用Waku展示了RSCs如何让React开发人员在组件级别访问异步服务器端请求和数据。

React服务器组件简介的特色图片

哇,最近关于React服务器组件(RSCs)的讨论声浪很大,但大部分时间,在阅读了互联网上最聪明的人的解释后,我并没有真正理解任何内容。但我后来花时间尝试了Waku,现在我觉得RSCs比我最初想的要简单得多。

什么是Waku?

Waku(wah-ku)或 わく 在日语中意味着“框架”。作为一个最小的React框架,它旨在加速初创公司和代理商构建中小型React项目的开发人员的工作。根据Waku网站的介绍,这些项目包括营销网站、轻量级电子商务和Web应用程序。

然而,网站介绍中遗漏的是,Waku支持React服务器组件——因此,如果你想亲自尝试它们,你不需要使用Next.js(对此我个人感到很感激)。值得一提的是,目前Waku正在快速开发中,应仅用于非生产项目。

React服务器组件简介

所以这是我的看法:RSCs让React开发人员可以在组件级别访问异步服务器端请求和结果数据。

在RSCs之前,像Next.js、Gatsby、Remix和Astro等框架都要求你在路由级别进行服务器端请求。

以下是上述每个框架中实现此目的的一些示例。

Next.js路由(应用路由器)

在此路由中,有一个名为getData的函数,该函数对GitHub API进行异步请求并返回响应,然后可以使用getData函数将其提取并提供给路由或页面。

// app/page.jsx

import ParentComponent from '../components/parent-component';

const Page = async () => {
  const data = await getData();

  return <ParentComponent data={data} />;
};

async function getData() {
  const response = await fetch('https://api.github.com/repos/vercel/next.js');
  const data = await response.json();

  return data;
}

export default Page;

Next.js路由(页面路由器)

在路由中,有一个名为getServerSideProps的函数,该函数对GitHub API进行异步请求并将响应返回给路由或页面通过data属性。

// pages/index.js

import ParentComponent from '../components/parent-component';

const Page = ({ data }) => {
  return <ParentComponent data={data} />;
};

export async function getServerSideProps() {
  const response = await fetch('https://api.github.com/repos/vercel/next.js');
  const data = await response.json();

  return { props: { data } };
}

export default Page;

Gatsby路由

在此路由中,有一个名为getServerData的函数,该函数对GitHub API进行异步请求并将响应返回给路由或页面通过data属性。

// src/pages/index.js

import ParentComponent from '../components/parent-component';

const Page = ({ data }) => {
  return <ParentComponent data={data} />;
};

export async function getServerData() {
  const response = await fetch('https://api.github.com/repos/gatsbyjs/gatsby');
  const data = await response.json();

  return { props: { data } };
}

export default Page;

Remix路由

在此路由中,有一个名为loader的函数,该函数对GitHub API进行异步请求并返回响应,然后可以使用useLoaderData钩子将其提取并使其可用于页面。

// app/routes/_index.jsx

import { useLoaderData } from '@remix-run/react';
import { json } from '@remix-run/node';

import ParentComponent from '../components/parent-component';

const Page = () => {
  const { data } = useLoaderData();

  return <ParentComponent data={data} />;
};

export const loader = async () => {
  const response = await fetch('https://api.github.com/repos/remix-run/remix');
  const data = await response.json();

  return json({
    data,
  });
};

export default Page;

Astro路由

// src/pages/index.astro

---
const response = await fetch('https://api.github.com/repos/withastro/astro');
const data = await response.json();

import ParentComponent from '../components/parent-component';
---

<ParentComponent data={data} />;

属性传递

你会注意到在所有这些示例中,数据通过名为data的属性传递给名为ParentComponent的组件。

ParentComponent

ParentComponent可能是这样的,其中数据再次通过名为ChildComponent的另一个组件传递。

// components/parent-component.js

import ChildComponent from './child-component';

const ParentComponent = ({ data }) => {
  return <ChildComponent data={data} />;
};

export default ParentComponent;
view raw

ChildComponent

最后,在ChildComponent中,你可能希望对这些数据进行一些操作;正如你所看到的,数据必须在到达目的地之前经过一些旅程。

// components/child-component.js

const ChildComponent = ({ data }) => {
  return <pre>{JSON.stringify(data, null, 2)}</pre>;
};

export default ChildComponent;

组件级数据获取

你可能知道,如果要重构此应用程序或移动Parent或Child组件,则还需要重新连接数据路径。

在应用程序的生命周期中,这种情况并

不罕见,取决于你的应用程序有多复杂,你需要在数据到达目的地之前走多远。

这就是RSCs真正有用的地方。这是我使用Waku时的方法。

Waku路由

使用Waku,我仍然有一个路由,但在此级别不会发生数据获取。

// src/pages/index.jsx

import ParentComponent from '../components/parent-component.js';

const Page = async () => {
  return <ParentComponent />;
};

export default Page;

export const getConfig = async () => {
  return {
    render: 'dynamic',
  };
};

Waku ParentComponent

ParentComponent仍然导入并返回ChildComponent,但没有属性,也没有将任何内容传递给ChildComponent。

// src/components/parent-component.jsx

import ChildComponent from './child-component.js';

const ParentComponent = () => {
  return <ChildComponent />;
};

export default ParentComponent;

Waku ChildComponent

这是ChildComponent;再次,没有通过属性传递数据。相反,所有数据获取都在组件内部、服务器端进行。

// src/components/child-component.tsx

const ChildComponent = async () => {
  const response = await fetch('https://api.github.com/repos/dai-shi/waku');
  const data = await response.json();

  return <pre>{JSON.stringify(data, null, 2)}</pre>;
};

export default ChildComponent;

对一些人来说很熟悉

这种在组件级别访问数据的方法可能对一些人来说很熟悉。对我来说也是如此,因为我曾是Gatsby的忠实用户。

Gatsby的useStaticQuery钩子

2019年2月,Gatsby引入了useStaticQuery钩子,虽然获取数据的方法大不相同(我并不打算将其与RSCs进行比较),但理论上有点类似,原因如下。

// src/components/child-component.js

import { useStaticQuery, graphql } from 'gatsby';

const ChildComponent = () => {
  const data = useStaticQuery(graphql`
    query {
      github {
        id
        owner {
          login
          url
        }
        description
      }
    }
  `);

  return <pre>{JSON.stringify(data, null, 2)}</pre>;
};

export default ChildComponent;

在Gatsby中,你从未使用GraphQL来获取数据(这是一个常见的误解);相反,你是在查询数据。数据获取是在构建时进行的,但使用useStaticQuery钩子,你能够从任何组件中、任何级别访问数据,而无需通过属性传递它。

对于RSCs,数据获取是在运行时进行的,因此虽然在RSCs和Gatsby的useStaticQuery钩子之间获取数据的方法有所不同,但当你能够从任何组件中访问数据时,你可以做出架构选择。

数据获取需要思考

然而,对于RSCs,你仍然需要考虑在哪些情况下在组件级别进行数据获取,而不是在路由级别进行数据获取。

一方面,是的,在组件所需的地方获取数据并访问数据很方便;但另一方面,如果在同一路由上有几个组件都在独立获取数据,这会对性能产生负面影响吗?

在某些情况下,可能仍然有意义在单个路由级别进行请求,并通过属性将结果数据传递给需要它的组件,而不是多个组件级别数据请求。值得在这里提到的是,采用明智的缓存策略可能会限制多个组件级别数据请求的影响。

最后的思考

在我看来,RSCs只是在构建数据密集型React应用程序时可供选择的另一个选项。我不认为它们能解决每个用例,也不打算如此。在许多情况下,它们可能不是正确的选择,但没关系。

正如每个开发人员在他们的职业生涯中多次说过的那样,这取决于情况。

从我使用Gatsby的经验来看,从组件中轻松访问数据有很多优势。因为逻辑、数据和最终的用户界面元素都清晰地位于同一个文件中,与追踪属性并尝试跟随数据路径相比,开发人员的体验通常更好。

总之,我真的很喜欢RSCs,我认为随着时间的推移,我们都会发现在开发过程中的最佳实践和需要注意的事项。但目前,我认为它们是一个非常酷的进步,并且我期待进一步的实验。如果你对自己尝试RSCs感兴趣,请尝试Waku。

分享于 2024-04-13

访问量 20

预览图片