很多初学者问“我应该学哪个框架?” 和“学一个框架之前需要学多少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中,但在Vue和Svelte的引擎盖下使用相同的模式。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 是一个函数,它接受一个状态并返回另一个状态。
这个模式被react和preact使用。它适合与 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 意味着缓存从状态计算的值,当它从状态中派生的变化时更新。它基本上是一种返回派生状态的效果。
在重新运行其组件功能的框架中,如react和preact,这允许在它所依赖的状态不变时再次选择退出部分组件。
对于其他框架,情况恰恰相反:它允许您选择部分组件进行响应式更新,同时缓存之前的计算。
对于我们简单的反应式系统,备忘录看起来像这样:
<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 还是其他地方。他们可以告诉您哪些方法适合他们的框架,这将帮助您更快地获得更好的解决方案。