Solid.js — Pod maską reaktywnego frameworka

Feb 19 2023
W tym artykule postaramy się dowiedzieć, w jaki sposób Solid.js jest w stanie osiągnąć precyzyjną reaktywność.

W tym artykule postaramy się dowiedzieć, w jaki sposób Solid.js jest w stanie osiągnąć precyzyjną reaktywność.

Wymagania wstępne:

Mam nadzieję, że ktokolwiek czyta ten artykuł ma podstawową wiedzę na temat React.js i wie trochę o Solid.js. Jeśli jeszcze nie sprawdziłeś strony solid.js, zachęcam do zapoznania się z niąhttps://www.solidjs.com/.

Solidny test porównawczy wydajności js

Zacznijmy od odpowiedzi na pytanie: Czym jest reaktywność?

Reaktywność to zdolność zmiennej (tablicy, łańcucha, liczby, obiektu itp.) do aktualizacji, gdy jej wartość lub jakakolwiek inna zmienna, do której się odwołuje, zostanie zmieniona po deklaracji.

Obecnie DOM, którego używamy, nie jest reaktywny, co oznacza, że ​​jeśli odwołam się do zmiennej JS w HTML i ta zmienna się zmieni, DOM nie zostanie automatycznie zaktualizowany o tę zmienną.

React.js używa wirtualnego DOM : tworzenie reprezentacji DOM w kategoriach obiektów i za każdym razem, gdy stan jest aktualizowany, sprawdzanie różnic między obiektami i próba zmiany DOM w minimalnych krokach. React działa w taki sposób, że za każdym razem, gdy stan jest aktualizowany, ponownie renderuje cały komponent.

Można argumentować, że reakcja nie jest z natury reaktywna. Ten artykuł zawiera więcej szczegółów.

Solid.js wykorzystuje sygnały : Serce systemu reaktywnego opiera się na modelu emitera zdarzeń. Nazywam to modelem „ publikuj-subskrybent” . Zobaczmy to w kategoriach Solid.js
Na przykład:

import { createSignal, createEffect } from "solid-js";

const [getCount, setCount] = createSignal(0);
// Here createSignal returns [getter, setter or publisher]

createEffect(() => console.log(getCount()));
// Here createEffect act as a subscriber to setCount event

// So whenever I'll do setCount it will log that count value 
// also it is triggered at first so you'll see 0 getting printed
setCount(getCount() + 1)

/**
Logs:
0
1
*/

To wszystko świetnie, ale nie rozmawialiśmy o tym, jak to działa z DOM?
Możesz sobie wyobrazić, że w tle DOM jest automatycznie zawijany w createEffect.
Więc kiedy widzisz

import { createSignal, createEffect } from "solid-js";

function App() {
  const [count, setCount] = useSignal(0);
  return <div>{count()}</div>
}

// It somehow gets converted into
function App() {
  const [count, setCount] = useSignal(0);
  return createEffect(() => <div>{count()}</div>)
}

Napisałem podstawowy fragment kodu w Solid; spróbujmy zrozumieć, co robi Solid.js.

import { render } from "solid-js/web";
import { createSignal } from "solid-js";

function Counter() {
  const [count, setCount] = createSignal(1);
  const increment = () => setCount(count() + 1);

  return (
    <>
    <button type="button" onClick={increment}>Click Me</button>
    <div>{count()}</div>
    </>
  );
}

render(() => <Counter />, document.getElementById("app")!);

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

/******* 
  1. If you see here the html got converted to string,
  Here the template function converts the string to actual HTML DOM
  
  function template(HTML) {
    const dom = document.createElement('template');
    dom.innerHTML = HTML;
    return dom.firstChild;
  }
*****/
const _tmpl$ = /*#__PURE__*/_$template(`<button type="button">Click Me</button>`, 2),
  _tmpl$2 = /*#__PURE__*/_$template(`<div></div>`, 2);

import { render } from "solid-js/web";
import { createSignal } from "solid-js";

function Counter() {
  const [count, setCount] = createSignal(1);
  const increment = () => setCount(count() + 1);

  return [(() => {
    const _el$ = _tmpl$.cloneNode(true);
    _el$.$$click = increment;
    return _el$;
  })(), (() => {
    const _el$2 = _tmpl$2.cloneNode(true);

    /******* 
      2. Here insert functions internally uses createEffect and 
         make DOM changes whenever increment function is called.
      
        function insert(parentElement, value) {
          createEffect(() => parentElement.innerHTML = value);
        }
    *****/

    _$insert(_el$2, count);
    return _el$2;
  })()];
}
render(() => _$createComponent(Counter, {}), document.getElementById("app"));
_$delegateEvents(["click"]);

Tak rozumiem, jak solid.js działa w tle i chciałbym usłyszeć opinię, jeśli gdzieś się pomyliłem.

Zasoby:

Rozmowa o reaktywności —https://dev.to/ryansolid/building-a-reactive-library-from-scratch-1i0p
https://www.youtube.com/watch?v=UhGV8yYnvQE

dom-wyrażenie —https://www.youtube.com/watch?v=jnZmG4hyNas