React 重蹈 Angular.js 覆辙?

48680611ece27aa9a64163e337ac849c.gif

【编者按】开源框架 react-admin 和 GreenFrame 创始人,Marmelab CEO François Zaninotto 针对 React 引进的服务器组件的新方法发布了自己的观点,虽然这是构建 Web 应用程序员的新方法,但并不适合现有大多数 React ,意味着现有应用引入该方法就得对应用进行重写,因此他希望React 团队认识到单页应用架构是一个正确的选择,并且短期内不会消失。希望团队能想一个更加折中的方法。

链接:https://marmelab.com/blog/2023/06/05/react-angularjs-moment.html

未经允许,禁止转载!

作者 | François Zaninotto       译者 | 弯月

出品 | CSDN(ID:CSDNnews)

2012年,Angular.js 一经推出便改变了前端开发的格局,迅速取得成功。仅在两年之后,Angular 团队推出了 Angular 2,然而他们根据一组不同的范例重写了整个原始库。许多开发人员,包括我自己,都不想重写现有的应用程序来适应这些新想法。对于新项目来说,Angular.js 不再是首选,因为其他框架也同样出色。

2015 年,我们开始使用 React 来构建前端。React 不仅拥有简单的架构,而且还注重组件,再加上稳定的生产力,无论代码库大小如何都是一个很好的选择。React 大受欢迎,社区发展迅速。最近,React 和 Next.js 团队一直在推广服务器组件,这是一种构建 Web 应用程序的新方法,但不适合大多数现有的 React 应用。

这种变化是否堪比从 Angular.js 到 Angular 2 的转变?React 是否正在重蹈 Angular.js 的覆辙?

注意:在本文中,我将讨论 React 和 Next.js 团队引入的新功能。由于这两个团队密切合作,因此很难说哪个团队负责哪个功能。因此,我将使用“React”来指代这两个团队。


6c59cf8ff2807650b9ebd5d9a6c28f80.png

重新学习一切 

React 的核心是一个视图库。这一点没有变化,对于 React 服务器组件,你仍然可以使用 JSX 构建组件,并渲染 props 传递进来的动态内容:

function Playlist({ name, tracks }) {
 return (
   

{name}

           {tracks.map((track, index) => (                     ))}
Title Artist Album Duration
{track.title} {track.artist} {track.album} {track.duration}
); }

然而,其他一切都随着服务器组件而发生了变化。数据获取不再依赖 useEffect 或 react-query;相反,你应该在异步组件中使用 fetch:

async function PlaylistFromId({ id }) {
    const response = await fetch(`/api/playlists/${id}`);
 if (!response.ok) {
 // This will activate the closest `error.js` Error Boundary
 throw new Error('Failed to fetch data');
 }
 const { name, tracks } = response.json();
 return ;
}

这个 fetch 函数不是浏览器 fetch。React 对其进行了加强,能够自动去除重复的请求。为什么说这是必要的?如果你需要通过组件树更深入地访问获取的数据,就不能将其放置在 React 上下文中,因为服务器组件中不能使用 useContext。因此,在组件树中的不同点访问同一个获取数据的推荐方法是,根据需要重新获取,并依靠 React 来避免重复请求。

默认情况下,无论响应缓存的标头如何,这个 fetch 函数都会缓存数据。实际的获取过程发生在构建时。

如果你想通过一个按钮来启动一个 POST 动作,就必须在表单中添加 fetch 函数,并使用服务器动作,这意味着使用一个带有 use server 的函数:

export function AddToFavoritesButton({ id }) {
    async function addToFavorites(data) {
        'use server';
        
        await fetch(`/api/tracks/${id}/favorites`, { method: 'POST' });
    }
    return (
       
         Add to Favorites ); }

常见的 React 钩子:useState、useContext、useEffect 将导致服务器组件出错。如果你需要这些钩子,就必须使用 use client,强制 React 在客户端渲染组件。注意,现在这个功能是默认启用的,而在Next.js中,甚至在服务器组件出现之前,它就是默认行为了。

React 重蹈 Angular.js 覆辙?_第1张图片

CSS-in-JS与服务器组件不兼容。如果你习惯了使用 sx 或 css 属性直接设置组件样式,则必须学习 CSS Modules、Tailwind 或 Sass。在我看来,这种变化感觉像是倒退了一步:

// in app/dashboard/layout.tsx
import styles from './styles.module.css';


export default function DashboardLayout({
    children,
}: {
    children: React.ReactNode,
}) {
 return {children};
}
/* in app/dashboard/styles.module.css */
.dashboard {
    padding: 24px;
}

那么,调试呢?我只能祝你好运。React DevTools 不显示 React 服务器组件的详细信息。你无法在浏览器中检查组件,查看它使用的 props 或其子组件。目前,调试 React 服务器组件只能求助于 console.log。

虽然基础的 JSX 保持不变,但服务器组件的基本思想与客户端 JS 完全不同。即便你是一名精通 React 的开发人员,也不一定对掌握服务器组件有很大帮助。基本上,你必须重新学习所有内容,除非你熟悉 PHP。

注意:公平地说,我提出的大多数问题都涉及到带有“alpha”标签的功能。这些问题可能会在稳定版本发布之前得到解决。


9cbfcce7a97406dced47b22d20bd97bc.png

生态系统为零

如上所述,获取数据不能再使用 react-query。事实证明,这不是唯一无法结合 React 服务器组件一起使用的库。如果你依赖下面的工具,那么就要开始寻找替代品了:

  •  material-ui

  •  chakra-ui

  •  Emotion

  •  styled-components

  •  React-query

  •  swr

  •  react-hook-form,

  •  适用于大多数SaaS 提供商的 SDK

  •  以及其他等等。

这些库都使用了标准的 React 钩子,从服务器组件调用时会失败。

React 重蹈 Angular.js 覆辙?_第2张图片

如果你需要这些库,则必须使用 use client 指令将它们封装在组件中,强制客户端渲染。

强调一下:React 服务器组件破坏了几乎所有现有的 React 第三方库,这些库的作者必须修改代码才能兼容。也许有些作者会修改代码,但有些不会。即使他们愿意修改,也需要一定的时间。

因此,如果你使用 React 服务器组件启动应用,则不能依赖现有的 React 生态系统。

更糟糕的是:客户端 React 提供了很多日常工作需要的工具,但服务器组件中并没有提供。例如,React Context 是管理依赖注入的绝佳解决方案。如果没有 React Context,服务器组件就需要一个依赖注入容器,类似于Angular 的方法。如果核心团队不提供,则不得不依靠社区。

与此同时,你必须手动编写很多代码。在没有 UI Kit、表单框架、智能 API 客户端以及你喜欢的 SaaS 的 React 集成的情况下构建 React 应用会变得非常具有挑战性。

当前的 React 生态系统是其最大的优势。这也是 React 如此广泛使用的原因。而 React 服务器组件打破了这一优势。


5f917cbfc63169eb0f7a108a446fcdbc.png

黑魔法太多了

服务器端渲染是一个已解决的问题。服务器端脚本接收请求、获取数据并生成 HTML。客户端渲染同样成熟。浏览器检索数据,客户端脚本更新 DOM。

React建议混合服务器端和客户端渲染,感觉就像是在使用黑魔法。你可以在服务器组件中使用客户端组件,反之亦然。

React 重蹈 Angular.js 覆辙?_第3张图片

当客户端组件渲染服务器组件时,React 服务器不会发送 HTML,而是发送组件树的文本表示。然后由客户端脚本在客户端渲染组件树。

如果你习惯使用 HTML 或 JSON 调试 AJAX请求,就会大吃一惊。这里由一个 RSC Wire 格式的例子(https://www.plasmic.app/blog/how-react-server-components-work#the-rsc-wire-format),React 使用这种格式将更新从服务器组件流式传输到客户端:

M1:{"id":"./src/ClientComponent.client.js","chunks":["client1"],"name":""}
S2:"react.suspense"
J0:["$","@1",null,{"children":[["$","span",null,{"children":"Hello from server land"}],["$","$2",null,{"fallback":"Loading tweets...","children":"@3"}]]}]
M4:{"id":"./src/Tweet.client.js","chunks":["client8"],"name":""}
J3:["$","ul",null,{"children":[["$","li",null,{"children":["$","@4",null,{"tweet":{...}}}]}],["$","li",null,{"children":["$","@4",null,{"tweet":{...}}}]}]]}]

这种格式没有文档,因为它是一个实现细节。

HTTP、JSON 和 JSX 如此流行,可读性功不可没。然而,React 服务器组件破坏了这种模式。

React服务器组件看似非常神秘,对大多数开发人员来说都很难理解或调试。不确定这种变化究竟是会提高生产力,还是会阻碍生产力。


7d5d41826ac808616fd2a049f31575c1.png

我们真的需要这个组件吗?

从第一原则触发考虑 Web 开发,可以合理地得出这样的结论:使用少量 AJAX 的服务器端渲染是构建 Web 应用程序的有效方法。Dan Abramov 在 2023年 Remix 大会的演讲中对React 服务器组件背后的动机做出了解释(https://www.youtube.com/watch?v=zMf_xeGPn6s&ab_channel=Remix):

React 重蹈 Angular.js 覆辙?_第4张图片

这种架构非常适合电子商务网站、博客以及其他对 SEO 有强烈要求的、以内容为中心的网站。

然而,这并不是一个新概念。多年来, 这种架构一直用于 Rails 中的 Hotwire 或 Symfony 应用程序等工具。

此外,服务器组件旨在解决的一些问题(如数据获取、部分渲染等)已被一些单页应用程序框架解决了,比如我们自己的 react-admin。还有一些问题,比如管理面板、SaaS、B2B 应用程序、内部应用程序、CRM、ERP、长期应用程序等,都算不上真正的问题。

这就是为什么许多 React 开发人员,包括我自己,都非常满意单页应用程序架构。当需要做一些服务器端渲染时,我可能会选择一个生态系统比 React 服务器组件更成熟的工具。

那么,如果我并不需要React 服务器组件,那么又何必如此担忧呢?


729e3cce544cc5fb2c596ef6c5729ee2.png

构建 React 应用的标准方法

我担心的第一个问题是,React 的这种变化是在阻止人们使用单页应用程序架构。或者说,React不鼓励人们在没有框架的情况下使用 React,然而React 框架本身却开始推崇服务器端渲染。

React 重蹈 Angular.js 覆辙?_第5张图片

我担心的第二个问题是,官方 React.js 文档建议使用 Next.js。而 Next.js 官方文档建议从 13.4 版开始使用 React 服务器组件。

换句话说,根据官方文档,React 服务器组件是构建 React 应用程序的默认方式。React 生态系统的新手自然会使用它们。

我认为这还为时过早。 Dan Abramov 也认为:

“为了让新范式发挥作用,我们还需要付出大量努力。”

React服务器组件需要新一代路由器、新一代捆绑器。但这些范式仍处于 alpha 阶段,尚未准备好投入生产。

那么,为什么 Next.js 如此激进呢?

我不得不认为,Next.js 的新方向并不是为了帮助开发者,而是为了帮助 Vercel 销售 React。你无法真正围绕 SPA 销售服务:一旦编译,SPA 就是一个可以在任何地方免费托管的单个 JS 文件。但是服务器端渲染的应用需要服务器才能运行。服务器是可以销售的产品。也许我是一个阴谋论者,但我看不出还有其他理由像这样破坏 React 生态系统。


c413a742452b5d1c9ab75c4967e5fcfb.png

现有应用不受影响

与 Angular.js 到 Angular 2 的过渡不同,React 服务器组件的引入并不是重大变化。现有的单页应用程序仍然可以使用最新版本的 React。使用 Pages 路由器构建的现有 Next.js应用程序也可以正常工作。

那么,问题:“React 会重蹈 Angular.js 的覆辙吗?”答案是,不会。

但如今开始一个新项目,你会选择什么?具有成熟工具和生态系统(单页应用)的健壮架构,还是 React 团队正在强推的新框架(服务器组件)?这是一个艰难的选择,人们可能会寻找替代方案,而不是冒险做错误的选择。

我个人认为,React 希望通过一个工具满足所有 Web 开发人员需求的愿景过于激进,或者说当前的解决方案不正确。Next.js 文档中有一个下拉列表,允许读者在App 路由器(服务器组件)和 Pages 路由器之间进行选择。如果一个工具提供两种截然不同的方法来做同一件事,那么它还是同一个工具吗? 

React 重蹈 Angular.js 覆辙?_第6张图片

所以,问题:“React 是否会因为过于激进而损害整个社区?”我认为答案是肯定的。

7f42d91214d1f7cbc37f5689ecd7ea17.png

总结

也许服务器组件代表服务器端框架的进步,或者至少,等到准备好投入生产,它们真的能够发挥积极的作用。但对于更广泛的 React 社区来说,我害怕这一变化会导致社区分裂,并有可能危及 React 多年来建立的优势。

我希望 React 和 Next.js 团队采用更加折中的方法。我希望 React 团队认识到单页应用架构是一个正确的选择,并且短期内不会消失。我更希望看到 Next.js 在他们的文档中淡化服务器组件,或者至少明确标注“alpha”功能。

也许是我过于急躁,也许这种变化代表了未来的趋势。也许开发人员注定要不断地在范式之间来回转换,这就是这个行业的本质。

推荐阅读:

▶“上4休3”公司不建议新公司模仿;甲骨文组队,欲挑战微软OpenAI组合;Qt Creator 11 Beta发布|极客头条

▶2023 开放原子全球开源峰会在北京成功举办

▶谷歌 Alpha 家族再添“猛将”:AlphaDev 重磅亮相,打破多年计算瓶颈,新排序算法提速 70%!

你可能感兴趣的:(react.js,angular.js,javascript,ecmascript,前端)