现代框架背后的概念

2023-11-10

很多初学者问“我应该学哪个框架?” 和“学一个框架之前需要学多少JS或TS?” - 无数自以为是的文章都在宣传作者首选框架或库的优势,而不是向读者展示其背后的概念以做出明智的决定。那么让我们先解决第二个问题:

“学一个框架之前要学多少JS/TS?”

尽可能多地让你理解它们所基于的概念。您将需要了解基本数据类型、函数、基本运算符和文档对象模型 (DOM),这是 HTML 和 CSS 在 JS 中的表示。虽然除此之外的一切都不会受到伤害,但并不严格要求精通框架或库。

如果你是一个完全的初学者,猫的 JS可能是你第一步的好资源。继续前进,直到您感到自信为止,然后继续前进,直到您再次感到自信为止。那是你了解足够的 JS/TS 并可以转向框架的时候。其余的你可以边走边学。

“你指的是什么概念?”

  • 状态
  • 效果
  • 记忆化
  • 模板和渲染

所有现代框架都从这些概念中派生出它们的功能。

状态

状态只是为您的应用程序提供动力的数据。它可能在全局级别上,适用于应用程序的较大部分,或适用于单个组件。让我们以一个简单的计数器为例。它保留的计数是状态。我们可以读取状态并写入状态以增加计数。

最简单的表示通常是一个变量,其中包含我们的状态所包含的数据:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-name-color)">count</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">increment</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-name-color)">count</span><span style="color:var(--syntax-error-color)">++</span><span style="color:var(--syntax-text-color)">;</span> <span style="color:var(--syntax-text-color)">};</span>
<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">button</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">document</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">createElement</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">button</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-name-color)">button</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">textContent</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">count</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-name-color)">button</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">addEventListener</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">click</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">increment</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-text-color)">document</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">body</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">appendChild</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">button</span><span style="color:var(--syntax-text-color)">);</span>
</code></span></span>

但是此代码有一个问题:对 的更改count(如 所做的更改increment)不会更新按钮的文本内容。我们可以手动更新所有内容,但这对于更复杂的用例来说并不能很好地扩展。

更新其用户的能力count称为反应性。这是通过订阅并重新运行应用程序的订阅部分来更新的。

几乎每个现代前端框架和库都有一种响应式管理状态的方法。解决方案分为三部分,至少采用其中之一或混合使用:

  • 可观察量/信号
  • 不可变更新的协调
  • 转译

可观察量/信号

Observables 基本上是允许通过订阅阅读器的函数进行读取的结构。然后订阅者在更新时重新运行:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">state</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">initialValue</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">({</span>
  <span style="color:var(--syntax-name-color)">_value</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-name-color)">initialValue</span><span style="color:var(--syntax-text-color)">,</span>
  <span style="color:var(--syntax-name-color)">get</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-declaration-color)">function</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-comment-color)">/* subscribe */</span><span style="color:var(--syntax-text-color)">;</span>
    <span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">_value</span><span style="color:var(--syntax-text-color)">;</span> 
  <span style="color:var(--syntax-text-color)">},</span>
  <span style="color:var(--syntax-name-color)">set</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-declaration-color)">function</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">value</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">_value</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">value</span><span style="color:var(--syntax-text-color)">;</span>
    <span style="color:var(--syntax-comment-color)">/* re-run subscribers */</span><span style="color:var(--syntax-text-color)">;</span>
  <span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">});</span>
</code></span></span>

这个概念的第一个用途是在knockout中,它使用带有和不带参数的相同函数来进行写/读访问。

这种模式目前正在作为信号复兴,例如在Solid.js和preact signals中,但在VueSvelte的引擎盖下使用相同的模式。RxJS为Angular的反应层提供动力,是这一原则的延伸,超越了简单状态,但有人可能会争辩说,它对复杂性进行建模的能力是一整套瞄准你脚下的枪支。Solid.js还以存储(可以通过 setter 操作的对象)和可变(可以像普通 JS 对象或Vue中的状态一样处理嵌套状态对象的对象)的形式进一步抽象这些信号。

不可变状态的协调

不变性意味着如果一个对象的属性发生变化,整个对象引用必须改变,所以简单的引用比较可以很容易地检测到是否有变化,这就是协调器所做的。

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">state1</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">{</span>
  <span style="color:var(--syntax-name-color)">todos</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">[{</span> <span style="color:var(--syntax-name-color)">text</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">understand immutability</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">complete</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-declaration-color)">false</span> <span style="color:var(--syntax-text-color)">}],</span>
  <span style="color:var(--syntax-name-color)">currentText</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">''</span>
<span style="color:var(--syntax-text-color)">};</span>
<span style="color:var(--syntax-comment-color)">// updating the current text:</span>
<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">state2</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">{</span>
  <span style="color:var(--syntax-name-color)">todos</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-name-color)">state1</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">todos</span><span style="color:var(--syntax-text-color)">,</span>
  <span style="color:var(--syntax-name-color)">currentText</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">understand reconciliation</span><span style="color:var(--syntax-string-color)">'</span>
<span style="color:var(--syntax-text-color)">};</span>
<span style="color:var(--syntax-comment-color)">// adding a to-do:</span>
<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">state3</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">{</span>
  <span style="color:var(--syntax-name-color)">todos</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">[</span>
    <span style="color:var(--syntax-name-color)">state</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">todos</span><span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-text-color)">],</span>
    <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-name-color)">text</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">understand reconciliation</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">complete</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-declaration-color)">true</span> <span style="color:var(--syntax-text-color)">}</span>
  <span style="color:var(--syntax-text-color)">],</span>
  <span style="color:var(--syntax-name-color)">currentText</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">''</span>
<span style="color:var(--syntax-text-color)">};</span>

<span style="color:var(--syntax-comment-color)">// this breaks immutability:</span>
<span style="color:var(--syntax-name-color)">state3</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">currentText</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">I am not immutable!</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">;</span>
</code></span></span>

如您所见,未更改项目的引用被重新使用。如果协调器检测到不同的对象引用,它会再次使用状态(道具、备忘录、效果、上下文)运行所有组件。由于读取访问是被动的,这需要手动指定对反应值的依赖性。

显然,您不是以这种方式定义状态。您可以从现有属性构建它,也可以使用所谓的缩减器。reducer 是一个函数,它接受一个状态并返回另一个状态。

这个模式被reactpreact使用。它适合与 vDOM 一起使用,我们将在稍后描述模板时探讨它。

并非每个框架都使用其 vDOM 来使状态完全响应。Mithril.JS,例如,在组件中设置的事件之后从状态变化中更新;否则你必须m.redraw()手动触发。

转译

转译是一个构建步骤,它重写我们的代码以使其在旧浏览器上运行或赋予它额外的能力;在这种情况下,该技术用于将简单变量更改为反应系统的一部分。

Svelte基于一个转译器,该转译器还通过看似简单的变量声明和访问为他们的反应式系统提供动力。

顺便说一句,Solid.js使用转译,但不是为了它的状态,只是为了模板。

效果

在大多数情况下,我们需要对反应状态做更多的事情,而不是从中派生并渲染到 DOM 中。我们必须管理副作用,这些都是由于视图更新之外的状态更改而发生的所有事情(尽管像Solid.js这样的一些框架也将视图更改视为效果)。

还记得订阅处理被故意遗漏的状态的第一个例子吗?让我们填写这个来处理效果作为对更新的反应:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">context</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">[];</span>

<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">state</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">initialValue</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">({</span>
  <span style="color:var(--syntax-name-color)">_subscribers</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-declaration-color)">new</span> <span style="color:var(--syntax-text-color)">Set</span><span style="color:var(--syntax-text-color)">(),</span>
  <span style="color:var(--syntax-name-color)">_value</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-name-color)">initialValue</span><span style="color:var(--syntax-text-color)">,</span>
  <span style="color:var(--syntax-name-color)">get</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-declaration-color)">function</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">current</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">context</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">at</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-error-color)">-</span><span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-text-color)">);</span>
    <span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">current</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">_subscribers</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">add</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">current</span><span style="color:var(--syntax-text-color)">);</span> <span style="color:var(--syntax-text-color)">}</span>
    <span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">_value</span><span style="color:var(--syntax-text-color)">;</span>
  <span style="color:var(--syntax-text-color)">},</span>
  <span style="color:var(--syntax-name-color)">set</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-declaration-color)">function</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">value</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">_value</span> <span style="color:var(--syntax-error-color)">===</span> <span style="color:var(--syntax-name-color)">value</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-declaration-color)">return</span><span style="color:var(--syntax-text-color)">;</span> <span style="color:var(--syntax-text-color)">}</span>
    <span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">_value</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">value</span><span style="color:var(--syntax-text-color)">;</span>
    <span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">_subscribers</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">forEach</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">sub</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-name-color)">sub</span><span style="color:var(--syntax-text-color)">());</span>
  <span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">});</span>

<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">effect</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">fn</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
  <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">execute</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-name-color)">context</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">push</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">execute</span><span style="color:var(--syntax-text-color)">);</span>
    <span style="color:var(--syntax-declaration-color)">try</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-name-color)">fn</span><span style="color:var(--syntax-text-color)">();</span> <span style="color:var(--syntax-text-color)">}</span> <span style="color:var(--syntax-declaration-color)">finally</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-name-color)">context</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">pop</span><span style="color:var(--syntax-text-color)">();</span> <span style="color:var(--syntax-text-color)">}</span>
  <span style="color:var(--syntax-text-color)">};</span>
  <span style="color:var(--syntax-name-color)">execute</span><span style="color:var(--syntax-text-color)">();</span>
<span style="color:var(--syntax-text-color)">};</span>
</code></span></span>

这基本上是对preact信号Solid.js中反应状态的简化,没有错误处理和状态突变模式(使用接收前一个值并返回下一个值的函数),但这很容易添加。

它允许我们使前面的示例具有反应性:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">count</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">state</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">increment</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-name-color)">count</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-declaration-color)">set</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">count</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-declaration-color)">get</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-error-color)">+</span> <span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">button</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">document</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">createElement</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">button</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-name-color)">effect</span><span style="color:var(--syntax-text-color)">(()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
  <span style="color:var(--syntax-name-color)">button</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">textContent</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">count</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-declaration-color)">get</span><span style="color:var(--syntax-text-color)">();</span>
<span style="color:var(--syntax-text-color)">});</span>
<span style="color:var(--syntax-name-color)">button</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">addEventListener</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">click</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">increment</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-text-color)">document</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">body</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">appendChild</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">button</span><span style="color:var(--syntax-text-color)">);</span>
</code></span></span>

☝使用您的开发人员工具在空白页面中尝试上述两个代码块。

在大多数情况下,框架允许不同的时间安排,让效果在渲染 DOM 之前、期间或之后运行。

记忆化

Memoization 意味着缓存从状态计算的值,当它从状态中派生的变化时更新。它基本上是一种返回派生状态的效果。

在重新运行其组件功能的框架中,如reactpreact,这允许在它所依赖的状态不变时再次选择退出部分组件。

对于其他框架,情况恰恰相反:它允许您选择部分组件进行响应式更新,同时缓存之前的计算。

对于我们简单的反应式系统,备忘录看起来像这样:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">memo</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">fn</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
  <span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-name-color)">memoized</span><span style="color:var(--syntax-text-color)">;</span>
  <span style="color:var(--syntax-name-color)">effect</span><span style="color:var(--syntax-text-color)">(()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">memoized</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
      <span style="color:var(--syntax-name-color)">memoized</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-declaration-color)">set</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">fn</span><span style="color:var(--syntax-text-color)">());</span>
    <span style="color:var(--syntax-text-color)">}</span> <span style="color:var(--syntax-declaration-color)">else</span> <span style="color:var(--syntax-text-color)">{</span>
      <span style="color:var(--syntax-name-color)">memoized</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">state</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">fn</span><span style="color:var(--syntax-text-color)">());</span>
    <span style="color:var(--syntax-text-color)">}</span>
  <span style="color:var(--syntax-text-color)">});</span>
  <span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-name-color)">memoized</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-declaration-color)">get</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">};</span>
</code></span></span>

模板和渲染

现在我们有了纯的、派生的和缓存形式的状态,我们想把它展示给用户。在我们的示例中,我们直接使用 DOM 来添加按钮并更新其文本内容。

为了对开发人员更加友好,几乎所有现代框架都支持一些特定领域的语言来编写类似于代码中所需输出的内容。尽管有不同的风格,比如.jsx,.vue.svelte文件,但都归结为用类似于 HTML 的代码表示 DOM,因此基本上

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-text-color)"><</span><span style="color:var(--syntax-error-color)">div</span><span style="color:var(--syntax-text-color)">></span>Hello, World<span style="color:var(--syntax-text-color)"></</span><span style="color:var(--syntax-error-color)">div</span><span style="color:var(--syntax-text-color)">></span>

<span style="color:var(--syntax-comment-color)">// in your JS</span>
<span style="color:var(--syntax-comment-color)">// becomes in your HTML:</span>

<span style="color:var(--syntax-text-color)"><</span><span style="color:var(--syntax-error-color)">div</span><span style="color:var(--syntax-text-color)">></span>Hello, World<span style="color:var(--syntax-text-color)"></</span><span style="color:var(--syntax-error-color)">div</span><span style="color:var(--syntax-text-color)">></span>
</code></span></span>

“我把状态放在哪里?” 你可能会问。很好的问题。在大多数情况下,{}用于表示属性和节点周围的动态内容。

最常用的 JS 模板语言扩展无疑是 JSX。对于React,它被编译为纯 JavaScript,其方式允许它创建 DOM 的虚拟表示,称为虚拟文档对象模型或简称 vDOM 的内部视图状态。

这是基于这样的前提,即创建对象比访问 DOM 快得多,所以如果你能用当前的替换后者,你可以节省时间。但是,如果您在任何情况下都有大量 DOM 更改或创建无数对象而没有更改,则此解决方案的好处很容易变成必须通过记忆来规避的缺点。

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)">// original code</span>
<span style="color:var(--syntax-text-color)"><</span><span style="color:var(--syntax-error-color)">div</span><span style="color:var(--syntax-text-color)">></span>Hello, <span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-name-color)">name</span><span style="color:var(--syntax-string-color)">}</span><span style="color:var(--syntax-text-color)"></</span><span style="color:var(--syntax-error-color)">div</span><span style="color:var(--syntax-text-color)">></span>

<span style="color:var(--syntax-comment-color)">// transpiled to js</span>
<span style="color:var(--syntax-name-color)">createElement</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-string-color)">div</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-declaration-color)">null</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-string-color)">Hello, </span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">name</span><span style="color:var(--syntax-text-color)">);</span>

<span style="color:var(--syntax-comment-color)">// executed js</span>
<span style="color:var(--syntax-text-color)">{</span>
  <span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-string-color)">$$typeof</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">Symbol</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">react</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">element</span><span style="color:var(--syntax-text-color)">),</span>
  <span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-string-color)">type</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-string-color)">div</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-text-color)">,</span>
  <span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-string-color)">key</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-declaration-color)">null</span><span style="color:var(--syntax-text-color)">,</span>
  <span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-string-color)">ref</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-declaration-color)">null</span><span style="color:var(--syntax-text-color)">,</span>
  <span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-string-color)">props</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-string-color)">children</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-string-color)">Hello, World</span><span style="color:var(--syntax-string-color)">"</span>
  <span style="color:var(--syntax-text-color)">},</span>
  <span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-string-color)">_owner</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-declaration-color)">null</span>
<span style="color:var(--syntax-text-color)">}</span>

<span style="color:var(--syntax-comment-color)">// rendered vdom</span>
<span style="color:var(--syntax-comment-color)">/* HTMLDivElement */</span><span style="color:var(--syntax-text-color)"><</span><span style="color:var(--syntax-error-color)">div</span><span style="color:var(--syntax-text-color)">></span>Hello, World<span style="color:var(--syntax-text-color)"></</span><span style="color:var(--syntax-error-color)">div</span><span style="color:var(--syntax-text-color)">></span>
</code></span></span>

不过,JSX 不仅限于反应。例如,Solid 使用其转译器更彻底地更改代码:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)">// 1. original code</span>
<span style="color:var(--syntax-text-color)"><</span><span style="color:var(--syntax-error-color)">div</span><span style="color:var(--syntax-text-color)">></span>Hello, <span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-name-color)">name</span><span style="color:var(--syntax-text-color)">()</span><span style="color:var(--syntax-string-color)">}</span><span style="color:var(--syntax-text-color)"></</span><span style="color:var(--syntax-error-color)">div</span><span style="color:var(--syntax-text-color)">></span>

<span style="color:var(--syntax-comment-color)">// 2. transpiled to js</span>
<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">_tmpl$</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-comment-color)">/*#__PURE__*/</span><span style="color:var(--syntax-name-color)">_$template</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">`<div>Hello, </div>`</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-literal-color)">2</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-text-color)">(()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
  <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">_el$</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">_tmpl$</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">cloneNode</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">true</span><span style="color:var(--syntax-text-color)">),</span>
    <span style="color:var(--syntax-name-color)">_el$2</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">_el$</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">firstChild</span><span style="color:var(--syntax-text-color)">;</span>
  <span style="color:var(--syntax-name-color)">_$insert</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">_el$</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">name</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-declaration-color)">null</span><span style="color:var(--syntax-text-color)">);</span>
  <span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-name-color)">_el$</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">})();</span>

<span style="color:var(--syntax-comment-color)">// 3. executed js code</span>
<span style="color:var(--syntax-comment-color)">/* HTMLDivElement */</span><span style="color:var(--syntax-text-color)"><</span><span style="color:var(--syntax-error-color)">div</span><span style="color:var(--syntax-text-color)">></span>Hello, World<span style="color:var(--syntax-text-color)"></</span><span style="color:var(--syntax-error-color)">div</span><span style="color:var(--syntax-text-color)">></span>
</code></span></span>

虽然转译后的代码乍一看可能令人望而生畏,但解释这里发生的事情却相当简单。首先,创建包含所有静态部分的模板,然后克隆它以创建其内容的新实例,并添加动态部分并连接以根据状态更改进行更新。

Svelte 走得更远,不仅可以转换模板,还可以转换状态。

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)">// 1. original code</span>
<span style="color:var(--syntax-text-color)"><</span><span style="color:var(--syntax-error-color)">script</span><span style="color:var(--syntax-text-color)">></span>
let name = 'World';
setTimeout(() => <span style="color:var(--syntax-string-color)">{</span> <span style="color:var(--syntax-name-color)">name</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">you</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">;</span> <span style="color:var(--syntax-string-color)">}</span>, 1000);
<span style="color:var(--syntax-text-color)"></</span><span style="color:var(--syntax-error-color)">script</span><span style="color:var(--syntax-text-color)">></span>

<span style="color:var(--syntax-text-color)"><</span><span style="color:var(--syntax-error-color)">div</span><span style="color:var(--syntax-text-color)">></span>Hello, <span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-name-color)">name</span><span style="color:var(--syntax-string-color)">}</span><span style="color:var(--syntax-text-color)"></</span><span style="color:var(--syntax-error-color)">div</span><span style="color:var(--syntax-text-color)">></span>

<span style="color:var(--syntax-comment-color)">// 2. transpiled to js</span>
<span style="color:var(--syntax-comment-color)">/* generated by Svelte v3.55.0 */</span>
<span style="color:var(--syntax-declaration-color)">import</span> <span style="color:var(--syntax-text-color)">{</span>
        <span style="color:var(--syntax-name-color)">SvelteComponent</span><span style="color:var(--syntax-text-color)">,</span>
        <span style="color:var(--syntax-name-color)">append</span><span style="color:var(--syntax-text-color)">,</span>
        <span style="color:var(--syntax-name-color)">detach</span><span style="color:var(--syntax-text-color)">,</span>
        <span style="color:var(--syntax-name-color)">element</span><span style="color:var(--syntax-text-color)">,</span>
        <span style="color:var(--syntax-name-color)">init</span><span style="color:var(--syntax-text-color)">,</span>
        <span style="color:var(--syntax-name-color)">insert</span><span style="color:var(--syntax-text-color)">,</span>
        <span style="color:var(--syntax-name-color)">noop</span><span style="color:var(--syntax-text-color)">,</span>
        <span style="color:var(--syntax-name-color)">safe_not_equal</span><span style="color:var(--syntax-text-color)">,</span>
        <span style="color:var(--syntax-name-color)">set_data</span><span style="color:var(--syntax-text-color)">,</span>
        <span style="color:var(--syntax-name-color)">text</span>
<span style="color:var(--syntax-text-color)">}</span> <span style="color:var(--syntax-declaration-color)">from</span> <span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-string-color)">svelte/internal</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-text-color)">;</span>

<span style="color:var(--syntax-declaration-color)">function</span> <span style="color:var(--syntax-name-color)">create_fragment</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">ctx</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
        <span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-name-color)">div</span><span style="color:var(--syntax-text-color)">;</span>
        <span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-name-color)">t0</span><span style="color:var(--syntax-text-color)">;</span>
        <span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-name-color)">t1</span><span style="color:var(--syntax-text-color)">;</span>

        <span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-text-color)">{</span>
                <span style="color:var(--syntax-name-color)">c</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
                        <span style="color:var(--syntax-name-color)">div</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">element</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-string-color)">div</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-text-color)">);</span>
                        <span style="color:var(--syntax-name-color)">t0</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">text</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-string-color)">Hello, </span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-text-color)">);</span>
                        <span style="color:var(--syntax-name-color)">t1</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">text</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-comment-color)">/*name*/</span> <span style="color:var(--syntax-name-color)">ctx</span><span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-text-color)">]);</span>
                <span style="color:var(--syntax-text-color)">},</span>
                <span style="color:var(--syntax-name-color)">m</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">target</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">anchor</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
                        <span style="color:var(--syntax-name-color)">insert</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">target</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">div</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">anchor</span><span style="color:var(--syntax-text-color)">);</span>
                        <span style="color:var(--syntax-name-color)">append</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">div</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">t0</span><span style="color:var(--syntax-text-color)">);</span>
                        <span style="color:var(--syntax-name-color)">append</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">div</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">t1</span><span style="color:var(--syntax-text-color)">);</span>
                <span style="color:var(--syntax-text-color)">},</span>
                <span style="color:var(--syntax-name-color)">p</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">ctx</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-name-color)">dirty</span><span style="color:var(--syntax-text-color)">])</span> <span style="color:var(--syntax-text-color)">{</span>
                        <span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">dirty</span> <span style="color:var(--syntax-error-color)">&</span> <span style="color:var(--syntax-comment-color)">/*name*/</span> <span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-name-color)">set_data</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">t1</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-comment-color)">/*name*/</span> <span style="color:var(--syntax-name-color)">ctx</span><span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-text-color)">]);</span>
                <span style="color:var(--syntax-text-color)">},</span>
                <span style="color:var(--syntax-name-color)">i</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-name-color)">noop</span><span style="color:var(--syntax-text-color)">,</span>
                <span style="color:var(--syntax-name-color)">o</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-name-color)">noop</span><span style="color:var(--syntax-text-color)">,</span>
                <span style="color:var(--syntax-name-color)">d</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">detaching</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
                        <span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">detaching</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-name-color)">detach</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">div</span><span style="color:var(--syntax-text-color)">);</span>
                <span style="color:var(--syntax-text-color)">}</span>
        <span style="color:var(--syntax-text-color)">};</span>
<span style="color:var(--syntax-text-color)">}</span>

<span style="color:var(--syntax-declaration-color)">function</span> <span style="color:var(--syntax-name-color)">instance</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">$$self</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">$$props</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">$$invalidate</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
        <span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-name-color)">name</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">World</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">;</span>

        <span style="color:var(--syntax-name-color)">setTimeout</span><span style="color:var(--syntax-text-color)">(</span>
                <span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
                        <span style="color:var(--syntax-name-color)">$$invalidate</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">name</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">you</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">);</span>
                <span style="color:var(--syntax-text-color)">},</span>
                <span style="color:var(--syntax-literal-color)">1000</span>
        <span style="color:var(--syntax-text-color)">);</span>

        <span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-name-color)">name</span><span style="color:var(--syntax-text-color)">];</span>
<span style="color:var(--syntax-text-color)">}</span>

<span style="color:var(--syntax-declaration-color)">class</span> <span style="color:var(--syntax-name-color)">Component</span> <span style="color:var(--syntax-declaration-color)">extends</span> <span style="color:var(--syntax-name-color)">SvelteComponent</span> <span style="color:var(--syntax-text-color)">{</span>
        <span style="color:var(--syntax-declaration-color)">constructor</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">options</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
                <span style="color:var(--syntax-declaration-color)">super</span><span style="color:var(--syntax-text-color)">();</span>
                <span style="color:var(--syntax-name-color)">init</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">this</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">options</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">instance</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">create_fragment</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">safe_not_equal</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">{});</span>
        <span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">}</span>

<span style="color:var(--syntax-declaration-color)">export</span> <span style="color:var(--syntax-declaration-color)">default</span> <span style="color:var(--syntax-name-color)">Component</span><span style="color:var(--syntax-text-color)">;</span>

<span style="color:var(--syntax-comment-color)">// 3. executed JS code</span>
<span style="color:var(--syntax-comment-color)">/* HTMLDivElement */</span><span style="color:var(--syntax-text-color)"><</span><span style="color:var(--syntax-error-color)">div</span><span style="color:var(--syntax-text-color)">></span>Hello, World<span style="color:var(--syntax-text-color)"></</span><span style="color:var(--syntax-error-color)">div</span><span style="color:var(--syntax-text-color)">></span>
</code></span></span>

也有例外。例如,在Mithril.js中,虽然可以使用 JSX,但我们鼓励您编写 JS:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)">// 1. original JS code</span>
<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">Hello</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">{</span>
  <span style="color:var(--syntax-name-color)">name</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">World</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">,</span>
  <span style="color:var(--syntax-name-color)">oninit</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-name-color)">setTimeout</span><span style="color:var(--syntax-text-color)">(()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-name-color)">Hello</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">name</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">you</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">;</span>
    <span style="color:var(--syntax-name-color)">m</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">redraw</span><span style="color:var(--syntax-text-color)">();</span>
  <span style="color:var(--syntax-text-color)">},</span> <span style="color:var(--syntax-literal-color)">1000</span><span style="color:var(--syntax-text-color)">),</span>
  <span style="color:var(--syntax-name-color)">view</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-name-color)">m</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">div</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">Hello, </span><span style="color:var(--syntax-string-color)">'</span> <span style="color:var(--syntax-error-color)">+</span> <span style="color:var(--syntax-name-color)">Hello</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">name</span> <span style="color:var(--syntax-error-color)">+</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">!</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">};</span>

<span style="color:var(--syntax-comment-color)">// 2. executed JS code</span>
<span style="color:var(--syntax-comment-color)">/* HTMLDivElement */</span><span style="color:var(--syntax-error-color)"><</span><span style="color:var(--syntax-name-color)">div</span><span style="color:var(--syntax-error-color)">></span><span style="color:var(--syntax-name-color)">Hello</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">World</span><span style="color:var(--syntax-error-color)"><</span><span style="color:var(--syntax-string-color)">/div</span>>
</code></span></span>

虽然大多数人会发现开发人员缺乏经验,但其他人更喜欢完全控制他们的代码。根据他们旨在解决的问题,缺少转译步骤甚至可能是有益的。

许多其他框架允许在不进行转译的情况下使用,尽管很少有人这样推荐。

“我现在应该学习什么框架或库?”

我有一些好消息和一些坏消息要告诉你。

坏消息是:没有灵丹妙药。没有哪个框架在每个方面都比其他框架好得多。他们每个人都有自己的优势和妥协。React有它的钩子规则,Angular缺乏简单的信号,Vue缺乏向后兼容性,Svelte的伸缩性不太好,Solid.js禁止解构,而Mithril.js并不是真正的反应式,仅举几例。

好消息是:没有错误的选择——至少,除非项目的要求真的很有限,无论是在包大小还是性能方面。每个框架都会完成它的工作。有些人可能需要解决他们的设计决策,这可能会使您的速度变慢,但无论如何您都应该能够获得可行的结果。

话虽这么说,没有框架也可能是一个可行的选择。许多项目都被过度使用 JavaScript 破坏了,而带有一些交互性的静态页面也可以完成这项工作。

现在您已经了解了这些框架和库应用的概念,请选择最适合您当前任务的概念。不要害怕在下一个项目中切换框架。没有必要学习所有这些。

如果你尝试一个新的框架,我发现最有帮助的事情之一就是连接到它的社区,无论是在社交媒体、discord、github 还是其他地方。他们可以告诉您哪些方法适合他们的框架,这将帮助您更快地获得更好的解决方案。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

现代框架背后的概念 的相关文章

  • 滚动时的 CSS 背景模糊

    我有固定的背景图像 滚动时我希望图像变得模糊 我知道如何在 css 中进行模糊 但在特定的滚动位置进行 这是一个例子 https medium com good music f160ba9e6c52 https medium com goo
  • 通过 JavaScript 获取表单名称

    我有一个简单的问题 但我在网上找不到好的解决方案 我有这个 HTML 代码
  • 如何在React Native Android中获取响应头?

    您好 我想在获取 POST 请求后获取响应标头 我尝试调试看看里面有什么response with console log response 我可以从以下位置获取响应机构responseData但我不知道如何获取标题 我想同时获得标题和正文
  • 两列表:一列尽可能小,另一列占据其余部分

    我在 div 中有一个 to columns 表 div table tbody tr td class action a a td td class content p Bigger text variable size p td tr
  • 如何使用 Scrapy 从网站获取所有纯文本?

    我希望在 HTML 呈现后 可以从网站上看到所有文本 我正在使用 Scrapy 框架使用 Python 工作 和xpath body text 我能够获取它 但是带有 HTML 标签 而且我只想要文本 有什么解决办法吗 最简单的选择是ext
  • React Router v4 不渲染组件

    React Router v4 渲染组件存在问题 在应用程序初始加载时 它将呈现与 URL 相对应的正确组件 但是 任何后续的组件Link单击不会呈现所需的组件 图书馆 反应路由器 4 2 2 https reacttraining com
  • IE 中的 XPath 查询使用从零开始的索引,但 W3C 规范是从一开始的。我应该如何处理差异?

    问题 我正在转换目前仅适用于 Internet Explorer 的相对较大的 Javascript 代码 以便使其也适用于其他浏览器 由于代码广泛使用 XPath 我们做了一些兼容性功能以使事情变得更容易 function selectN
  • 如何使用 Javascript 设置查询字符串

    有没有办法使用 javascript 设置查询字符串的值 我的页面有一个过滤器列表 单击该列表时 它将更改右侧的页内结果窗格 我正在尝试更新 url 的查询字符串值 因此如果用户离开页面 然后单击 后退 按钮 他们将返回到最后一个过滤器选择
  • onclick 事件中未调用函数

    我想在每个 YouTube 链接的末尾添加一些 HTML 以在 litebox 中打开播放器 到目前为止 这是我的代码 document ready function var valid url new RegExp youtube com
  • 如何在另一个自定义 Hook 中使用返回值的自定义 Hook?

    我正在使用 React native 其中有一个名为的自定义 HookuseUser使用以下方法从 AWS Amplify 获取用户信息Auth getUserInfro方法 然后获取返回对象的一部分并用它设置一个状态变量 我还有另一个名为
  • 为什么我的交互式图像仅在 Internet Explorer 上出现故障?

    我的问题 我为自己制作了一个图像地图 交互式图像 它在 Chrome safari 和 Firefox 上完美运行 然而 当我在可怕的互联网浏览器上尝试它时 它真的很糟糕 这些小点应该扩展到更大的盒子中 在互联网浏览器上它要么不起作用 要么
  • 如何计算特定字符在字符串中出现的次数

    我正在尝试创建一个函数来查看数组中的任何字符是否在字符串中 如果是 有多少个 我尝试计算每一种模式 但是太多了 我尝试使用 Python 中的 in 运算符的替代方案 但效果不佳 function calc fit element var
  • 改变 JavaScript 中的顶部填充

    以下是我在 css 中设置顶部填充的方法 body font size font size px margin 0 padding 100px 0 20px 0 width 100 important 如何使用最简单的 javascript
  • Google Maps API (v3) 添加/更新标记

    编辑 它现在可以工作 但如果用户不允许或没有基于位置的服务 则不会加载 请参阅 jsfiddle 示例接受的答案评论 我已经浏览了一些教程和问题 但我无法安静地理解正在发生的事情 或者在这种情况下 没有发生 当用户单击链接时 我正在加载地图
  • Rails 3.1+ 的 Jasmine 与 Mocha JavaScript 测试 [已关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 我对茉莉花有经验并且非常喜欢它 有谁有 Jasmine 和 Mocha 的经验 特别是 Rails 的经验吗 我想知道是否值得转用 我已经在 J
  • 使用 CSS 折叠和展开元素

    我正在尝试构建一个页面 加载时仅可见标题 并且 当用户单击标题时 每个标题下方的表格会在隐藏和显示状态之间切换 我的限制是只能在 CSS 中执行此操作 这是我到目前为止想到的 https jsfiddle net Argoron c1ypx
  • 主页(网格)上的缩略图现在显得模糊。如何纠正?

    我不知道这看起来是否愚蠢 但从早上开始我就无法纠正这个突然出现在我的博客网站上的错误www candidopinions in http www candidopinions in 我有一个网格视图模板 其中博客文章中的特色图像作为调整大小
  • 什么是 WKWebView 中的 WKErrorDomain 错误 4

    fatal error LPWebView encounters an error Error Domain WKErrorDomain Code 4 A JavaScript exception occurred UserInfo 0x7
  • Flot 库将 y 轴设置为最小值 0 和最大值 24

    如何将 y 轴设置在 0 到 24 的范围内 这是我的代码 j plot j placeholder d1 xaxis mode time min new Date 2010 11 01 getTime max new Date 2011
  • 将数组从 jquery ajax 传递到代码后面

    我必须将二维数组传递给在asp net网页代码后面编写的页面方法我有一个变量objList作为二维数组 我使用以下代码来实现此目的 但没有成功 并且未调用页面方法 脚本语言 function BindTable objList ajax u

随机推荐

  • SQL Server数据库进阶

    批处理 将多条SQL语句作为一个整体去编译 生成一个执行计划 然后执行 为了将一个脚本分为多个批处理 可使用GO语句 GO语句的特点 GO语句必须自成一行 只有注释可以在同一行上 它使得自脚本的开始部分或者最近一个GO语句以后的所有语句编译
  • elementUI中,实现一个单元格内显示两行数据,并用其中一个数据进行排序。

    最近在公司中 有这样一个需求 表格中 一个单元格里面显示两行数据 并且可以使用其中一行进行排序 其中数据的样式也要实时变动 类似于下图 这样的话 elementUI中自带的prop就不适合了 所以 需要展示两行数据的地方 我们就用插槽来解决
  • 重叠社区发现-UEOC算法(unfold and extract overlapping communities)学习笔记

    本文提出了一种基于马尔可夫动力学模型的发现节点共享社区的算法UEOC 在UEOC方法中 为了检测出所有的自然群落 将马尔可夫随机游动方法与一种新的约束策略相结合 该策略基于相应的退火网络 21 用于展开每个群落 然后 利用一个借助电导的截止
  • 【Python编程入门】环境搭建

    作为一门跨平台的高级编程语言 Python可以运行在几乎所有主流的操作系统中 这也意味着 只要我们在本机电脑安装配置完Python环境后 便可以轻松愉快的学习Python语言了 这是一门值得大部分人学习的计算机编程语言知识 关于Python
  • angular自定义form表单元素-checkList

    实际使用form的时候 最外层的form的某个表单元素可能是个组合的 这种情况如果是可多场景复用的 最好封装一个表单元素 本文以组合复选框为例来说明下自定义表单元素的过程 实现效果 展示效果 html
  • TeamViewer三种许可证的区别是什么?

    很多想要购买TeamViewer正版许可证的用户 不清楚这三种许可证的区别 所以今天小编就为大家介绍一下 这三种许可证到底有何区别以及购买那种最划算 首先为大家介绍一下TeamViewer Business商业版许可证 如下图所示 图1 B
  • 汇编语言基础知识

    文章目录 80386常用寄存器 一 常用寄存器 1 1 通用寄存器 1 2 段寄存器 1 3 程序状态与控制寄存器 二 常用基本指令 2 1 数据传送指令 2 2 算术运算指令 2 2 1 加法指令 2 2 2 减法指令 2 2 3 乘法指
  • 查看使用systemctl启动日志

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 1 查看启动日志 journalctl f或者 journalctl xe 2 设置开机自启动 systemctl enable nginx service 3 启动ngi
  • 2023最新SSM计算机毕业设计选题大全(附源码+LW)之java制造类企业erp23725

    面对老师五花八门的设计要求 首先自己要明确好自己的题目方向 并且与老师多多沟通 用什么编程语言 使用到什么数据库 确定好了 在开始着手毕业设计 1 选择课题的第一选择就是尽量选择指导老师擅长的课题 其实说白一点 你们的指导老师每年都是那几个
  • C3P0连接池参数配置

  • Linux系统wget unable to resolve host address解决办法

    Linux系统运行yum安装rpm包的时候提示wget unable to resolve host addresswget 无法解析主机地址 这就能看出是DNS解析的问题 错误提示 wget unable to resolve host
  • 用于CTF(MISC)的kali虚拟机更改过程记录

    Kali更改记录 安装pip2 太多工具需要python2了 安装setuptools 18 5 wget https pypi python org packages source s setuptools setuptools 18 5
  • 面向对象的编程思想和Python的继承和多态,特殊方法,引用计数

    面向对象的编程思想和Python的类 访问和属性 继承 在上一文中我们了解到了 私有的属性的访问方式 实例名 类名 私有属性名 一 私有的属性如何对外提供公有的取值和赋值方法呢 提供公有的方法作为接口进行取值 例如 class Avg Sc
  • 思科路由器NAT配置详解(转)

    思科路由器NAT配置详解 转 网络技术 2010 07 11 17 48 14 阅读104 评论0 字号 大中小 订阅
  • ubuntu安装vscode_vscode远程开发配置

    Remote development是一个支持vscode远程开发的插件 非常方便在windows下调试远程linux系统上的代码 使用配置方式如下 首先windows和远端服务器都要安装ssh windows上启用ssh服务即可 linu
  • RBAC权限管理

    RBAC权限管理 RBAC应用最为广泛的权限管理模型 核心的三要素是 用户 角色 权限 但并不仅仅局限于这三个核心要素 基于企业规模 用户规模 运维复杂度 RBCA其实是有很多的变种 从理论角度 有所谓的RBAC0 RBAC1 RBAC2
  • python opencv cv2在图片中画mask掩码/掩膜

    python opencv cv2在图片中画mask掩膜 import cv2 import numpy as np from PIL import Image import matplotlib pyplot as plt mask th
  • 年度最火的AOA蓝牙室内定位原理

    AOA 定位方法 AOA 定位方法 主要是测量信号移动台和基站之间的到达角度 以基站为起点形成的射线必经过移动台 两条射线的交点即为移动台的位置 该方法只需两个基站就可以确定 MS 的估计位置 其定位示意图如图所示
  • 语音转文字,视频转文字的新大陆!--飞书(好用记得点个赞)

    语音转文字 视频转文字的新大陆 飞书 1 选择自己对应的系统 下载飞书 飞书是字节跳动于2016年自研的新一代一站式协作平台 网址 https www feishu cn 2 下载安装之后 使用手机号 邮箱等注册登录 点击会议 点击进入子菜
  • 现代框架背后的概念

    很多初学者问 我应该学哪个框架 和 学一个框架之前需要学多少JS或TS 无数自以为是的文章都在宣传作者首选框架或库的优势 而不是向读者展示其背后的概念以做出明智的决定 那么让我们先解决第二个问题 学一个框架之前要学多少JS TS 尽可能多地