声明式反应和控制反转

声明式反应和控制反转

Lin Clark — A Cartoon Intro to Fiber — React Conf 2017

概述

React 官方文档 设计原则 看部分,有这样一句话:

即使您的组件被描述为函数,当您使用 React 时,您也不会直接调用它们。 每个组件都返回需要渲染的描述,并且该描述可能包括用户编写的组件,例如 和特定于平台的组件,例如

. 由 React 来“展开” 在未来的某个时间点,并根据组件的渲染结果递归地实际应用更改到 UI 树。

即使组件写成功能组件, “React”负责渲染组件并将其应用到 DOM。 因此,这意味着最好不要直接调用函数,让 React 渲染,这与 React 的设计原则和 React 所针对的范式密切相关。在这篇文章中,我们将看看这个。

Quanta Frontend团队开发大部分web项目和webview项目都是用ReactJs+Typescript技术栈(+NextJs用于需要服务端渲染来支持SEO和在低端设备上提升性能的项目)。(以下简称React)付出了很多关注它的工作原理,并认为组织和分享它很重要。

声明式反应

在计算机科学中,声明式编程是一种编程范式 表达了一个逻辑 计算而不描述其控制流 . -wiki(英文)

声明式编程有两种含义。 ** 根据一个定义,“声明性”当程序描述它的样子而不是指示它应该如何完成时。** 据说根据另一个定义,当一个程序用函数式编程语言、逻辑编程语言或受限编程语言编写时,它是“声明性的” -wiki(en)

在讨论 React 什么是“声明式”之前,最好先看看什么是声明式。根据上述定义,“声明式”编程是“程序(或状态)是什么样的”,而不是“程序如何”在编写时到达目的地(命令式)。

声明式和命令式的区别 堆栈溢出글 ,这是通过在集合中过滤奇数的示例来解释的。命令式编程通过告诉编译器程序到达其目的地必须经过的所有步骤来解决问题:

  1. 创建结果集合

  2. 遍历集合中的每个数字

  3. 检查数字,如果是奇数,将其添加到结果中

    列表结果=新列表();
    foreach(集合中的变量编号)
    {
    if (num % 2 != 0) results.Add(num);
    }

另一方面,在声明式编程中,程序并不会一一告诉你要做什么才能到达目的地,而是“ 我想要的动作 编写指定“.

 var results = collection.Where(num => num % 2 != 0);

在这里,我们说的是“给我们所有奇怪的地方”,而不是“逐步浏览集合。检查这个项目,如果它很奇怪,将它添加到结果集合中。”

那么,从用户界面的角度来看,声明式编程和命令式编程之间的这种区别意味着什么? <div> 标签内 <h1> 假设我们要渲染一个带有标签的 HTML 文档,其中写有“Chocolate Cookie”这个短语。如果您以命令式编程方式呈现此 UI,您可能必须按顺序依次告诉它们操作 DOM 的顺序,如下所示: (对于每次交互,我们提供逐步的 DOM 突变以达到所需的 UI 状态。)

命令式方法是提供逐步的 DOM 突变,直到达到所需的 UI

 函数 addCookieToBody() {  
 const bodyTag = document.querySelector('body')  
 const divTag = document.createElement('div') 让 h1Tag = document.createElement('h1')  
 h1Tag.innerText = "巧克力曲奇" divTag.append(h1Tag)  
 bodyTag.append(divTag)  
 }

另一方面,在以声明式编程方式渲染的情况下,不是通知每一步渲染对应的屏幕, 渲染完成后,“声明”你想要看到的最终结果,并将渲染结果传递给 UI 库。 这就是我们使用 React 渲染组件的方式。

在开发一个需要使用 React 渲染的组件时,我们以一种告诉 React 在特定状态下要绘制的屏幕的最终外观的方式来开发它。 React 负责安排任务以呈现最终外观,并将其带到 DOM。 ( 我们不提供达到所需 UI 的分步说明。相反,我们为每个场景描述了我们想要的最终 UI。 )

声明式方法是在您描述所需 UI 的最终状态时

 函数 RenderCookie() {  
 返回 (  
 <div>  
 <h1>巧克力曲奇</h1>  
 </div>  
 )  
 }

React 以这种“声明式”的方式指导组件的开发,因此 React 开发者可以根据特定的状态“声明”最终的 UI 输出,而不必担心每次渲染时如何操作 DOM。 React Element 的形式,并将其传递给 React 以在 DOM 中反映它。

声明式风格,就像 react 一样,允许你通过说“它应该看起来像这样”来控制应用程序中的流程和状态。命令式风格可以扭转这种局面,并允许您通过说“这是您应该做的”来控制您的应用程序。 — 堆栈溢出

控制反转 (IoC)

您的程序将驱动提示并获得对每个提示的响应 .使用图形(甚至基于屏幕)的 UI UI 框架将包含这个主循环,而您的程序则为屏幕上的各个字段提供事件处理程序 . ** 程序的主要控制被颠倒了,从你那里移到了框架上。** -martinfowler

这样,当我“声明”要绘制到 React 的 UI 作为 React 元素包并将其传递给 React 时,React 实际上会在屏幕上绘制这个“声明”。这个过程自然地将把屏幕渲染到 DOM 的责任从开发者转移到了 React,这意味着通过操作 DOM 将 UI 绘制到屏幕上的控制被反转(Inversion of Control)。 ( 程序的主控被倒置,远离你以做出反应。)

将这种“渲染”责任从开发人员转移到 React 有很大的好处。

解决问题的基本抽象

如您所见,React 方式关注结果并在渲染代码块中进一步描述它。简单的说, ” ** 我希望在页面上呈现的内容看起来像这样,我不在乎你如何到达那里。**

一个好的运行时提供了与手头的问题相匹配的基本抽象。在这里,抽象意味着将你想要表达的 UI 和你实际渲染它需要处理的任务分开,任务调度、协调、DOM 控制等。 反正, 反应渲染! ”一句话,可以做到。这种抽象让我们有更多的时间去思考“渲染什么屏幕”,让 React 去“如何”完全渲染这个屏幕。

这可以说和Clean Architecture中讲到的Usecase Layer在同一个语境下,其实就是开发者使用一个叫做Render的usecase来声明UI,这个叫做Render的函数是如何实现的(Infrastructure),DOM是什么时候以及如何实现的被操纵,这是因为开发者不必担心每个任务是如何划分的。这是 ” React 的责任 没看到。

支持并发和批处理

这是一个微妙但强大的区别。由于您不调用该组件函数而是让 React 调用它, 这意味着 React 有权在必要时延迟调用它 .在其当前实现中,React 递归地遍历树并在单个滴答期间调用整个更新树的渲染函数。但是在未来它可能会开始延迟一些更新以避免丢帧。

React 负责通过使用组件的描述(有关 React 元素的信息)操作 DOM 来绘制屏幕 这意味着 React 可以根据需要对多个任务进行优先级渲染,或者推迟执行任务。 做。这是“在 React 18 中引入的” 并发反应 ”,需要比较快反映的事件的渲染任务,比如User Event(鼠标点击,键盘输入)事件,优先考虑,而Background Data Fetching等事件反映的比较晚。这意味着React可以做性能优化等。

另外,为了不阻塞浏览器每帧执行操作,可以在浏览器不占用调用栈的时候进行渲染操作,而为了性能优化,从概念上讲,批处理相同操作的批处理立即提供。所有这些功能都是由 React 提供的,并且不断得到改进和维护,因此开发人员不必担心。

如果有东西不在屏幕上,我们可以延迟任何与之相关的逻辑。如果数据到达的速度快于帧速率,我们可以合并和批量更新。我们可以优先考虑来自用户交互的工作(例如由按钮单击引起的动画)而不是不太重要的后台工作(例如渲染刚从网络加载的新内容),以避免丢帧。

让 React 负责渲染还有其他好处,请参阅 Dan Abramov 的“ React 作为 UI 运行时 “请参阅文章。

结论

React 是一个用于 UI 渲染的库。 对运行时的一个很好的抽象 提供。通过这种方式,开发者只需将组件的声明以 React 元素(Declarative)的形式提供给 React,React 就从开发者手中接过了将规范反射到 DOM 并渲染的职责(IoC)。

由于 React 所面向的设计原则,开发人员可以通过简单地更新 React 版本(例如 17 到 18)来提高渲染性能,同时保持组件的声明,以及用户需要提供的“UI”。 ”,也就是你可以更深入地思考屏幕。我通过引用官方 React 文档的一部分来结束这篇文章。

React 让创建交互式 UI 变得轻松。为应用程序中的每个状态设计简单的视图,当你的数据发生变化时,React 将有效地更新和呈现正确的组件。

参考

https://martinfowler.com/articles/injection.html#InversionOfControl

https://overreacted.io/react-as-a-ui-runtime/

https://alexsidorenko.com/blog/react-is-declarative-what-does-it-mean/

https://reactjs.org/docs/design-principles.html#scheduling

https://en.wikipedia.org/wiki/Declarative_programming

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明

本文链接:https://www.qanswer.top/22230/15400709

posted @ 2022-09-07 09:16  哈哈哈来了啊啊啊  阅读(73)  评论(0编辑  收藏  举报