当前位置:首页全部内容React 重蹈 Angular.js 覆辙?

React 重蹈 Angular.js 覆辙?

原标题:React 重蹈 Angular.js 覆辙?

【编者按】开源框架 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”来指代这两个团队。

重新学习一切

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

functionPlaylist( { name, tracks }) { return( < div> < h1> {name} </ h1> < table> < thead> < tr> < th> Title </ th> < th> Artist </ th> < th> Album </ th> < th> Duration </ th> </ tr> </ thead> < tbody> {tracks.map((track, index) => ( < trkey= {index}> < td> {track.title} </ td> < td> {track.artist} </ td> < td> {track.album} </ td> < td> {track.duration} </ td> </ tr> ))} </ tbody> </ table> </ div> ); }

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

asyncfunctionPlaylistFromId( { id }) { constresponse = awaitfetch( `/api/playlists/ ${id}` ); if(!response.ok) { // This will activate the closest `error.js` Error Boundary thrownewError( Failed to fetch data); } const{ name, tracks } = response.json; return< Playlistname= {name}tracks= {tracks}/> ; }

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

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

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

exportfunctionAddToFavoritesButton( { id }) { asyncfunctionaddToFavorites( data) { use server; awaitfetch( `/api/tracks/ ${id}/favorites` , { method: POST}); } return( < formaction= {addToFavorites}> < buttontype= “submit”> Add to Favorites </ button> </ form> ); }

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

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

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

exportdefaultfunctionDashboardLayout( {children,}: {children: React.ReactNode,}) { return< sectionclassName= {styles.dashboard}> {children} </ section> ; }/* in app/dashboard/styles.module.css */.dashboard {padding: 24px; }

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

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

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

生态系统为零

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

material-ui chakra-ui Emotion styled-components React-query swr react-hook-form, 适用于大多数SaaS 提供商的 SDK 以及其他等等。

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

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

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

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

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

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

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

黑魔法太多了

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

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

当客户端组件渲染服务器组件时,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服务器组件看似非常神秘,对大多数开发人员来说都很难理解或调试。不确定这种变化究竟是会提高生产力,还是会阻碍生产力。

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

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

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

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

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

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

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

构建 React 应用的标准方法

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

我担心的第二个问题是,官方 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 生态系统。

现有应用不受影响

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

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

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

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

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

总结

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

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

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

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

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

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

责任编辑:

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。
0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧