在 SolidJS 中,信号如何重复渲染到 DOM 中?

Ste*_*uss 2 solid-js

我想我对反应性方面的信号、反应、推导非常了解。

但是,我无法理解如何突然将它们放入函数中,App()并且信号可以在信号更新时重复更新到 DOM 中?

我想也许这个文档解释了它,但它似乎太复杂了,难以理解。能用几段话解释清楚吗?

例如,我想象

<div>{value()}</div>
Run Code Online (Sandbox Code Playgroud)

从哪里来value()

const [value, setValue] = createSignal(123);
Run Code Online (Sandbox Code Playgroud)

会有一些代码来产生一些 Reaction 来对 Signalvalue的更改做出反应并更新 DOM,但是它是如何发生的呢?这createSignal()和普通版一样createSignal()还是特别版,设置了一个 Reaction 来更新 DOM?另外相关的是,既然App()只运行一次,那么为什么render()需要采取() => <App />但不能只采取<App />作为它的第一个参数呢?如果App()仅运行一次,则意味着() => <App />仅运行一次。那么为什么不直接给出 a<App />呢?

snn*_*snn 5

组件被编译成效果,当信号值更新时,效果会被重新评估。我简单解释一下:

  1. 调用时createSignal会创建订阅者列表并返回一对函数:一个 setter 和一个 getter。每个信号都有自己的订阅者列表。

setter 函数设置下一个值,而 getter 函数返回存储的值。

  1. 调用时,getter 函数会获取存储的值,但在获取值之前,包装 getter 调用的效果将被添加到信号的订阅者列表中。

因此,读取一个值,换句话说,调用 getter as value(),会自动将效果插入到信号的订阅者列表中。

当组件编译成函数调用时,可以createEffect手动或自动创建此效果。JSX

因此,当信号更新时,将执行这些效果。

  1. JSX 组件被编译成效果,每当信号值发生变化时,它就会创建并更新 DOM 节点。

让我们看看组件是如何编译成效果的:

import { createSignal } from 'solid-js';

export const Counter = () => {
  const [count, setCount] = createSignal(0);

  return <div>{count()}</div>
};
Run Code Online (Sandbox Code Playgroud)

上述组件的编译输出如下:

import { createSignal } from 'solid-js';

import { template as _$template } from "solid-js/web";
import { insert as _$insert } from "solid-js/web";

const _tmpl$ = /*#__PURE__*/_$template(`<div></div>`, 2);

export const Counter = () => {
  const [count, setCount] = createSignal(0);
  return (() => {
    const _el$ = _tmpl$.cloneNode(true);
    _$insert(_el$, count);
    return _el$;
  })();
};
Run Code Online (Sandbox Code Playgroud)

请参阅行_$template(`<div></div>`, 2)_tmpl$.cloneNode(true)_$insert(_el$, count);

这里:

  • _$template函数创建一个反映组件 DOM 结构的模板。

  • cloneNode克隆模板。

  • $insert函数填充值并将返回的 DOM 元素插入到其父 DOM 元素中。

因此,更新 DOM 的不是 getter 的调用,而是重新运行整个效果。

为什么 render() 需要采用 () => 但不能只将其作为第一个参数?

该文档回答了您的问题。Solid 的运行时会跟踪谁拥有谁,以防止内存泄漏。需要传递一个函数来进行设置。

重要的是,第一个参数是一个函数:不要直接传递 JSX(如在 render(, ...) 中),因为这将在 render 可以设置根来跟踪 App 内的信号依赖关系之前调用 App。https://www.solidjs.com/docs/latest#render

因此,您可以将其视为<App />函数调用,或者更准确地视为函数的调用App。因此,您将为该函数提供一个值render

如果您不喜欢语法,可以像这样() => <App />传递函数:App

const dispose = render(App, document.getElementById("app"));
Run Code Online (Sandbox Code Playgroud)

重要的是您提供一个返回 JSX 元素的函数,该元素将用作应用程序的根元素。