Hablemos del futuro del framework front-end Signals

¡Signals está muy por delante en la selección actual de frameworks front-end!

En la última semana antes del Día Nacional, estaba revisando el código de React de un nuevo compañero de clase y descubrí que quería usar memo y useCallback para representar solo la parte del subcomponente modificado. De hecho, esta característica es difícil de lograr en React. Porque después de que cambie el estado de React, la función de renderizado se volverá a ejecutar. Es decir, después de llamar a setState en el componente, toda la función se ejecutará nuevamente.

React por sí solo no puede hacer eso. Pero el marco basado en Signals no hace esto: utiliza el enlace de estado automático y el seguimiento de dependencias, de modo que después de que cambie el estado actual, solo volverá a ejecutar el bloque de código que usa el estado.

Personalmente, no expliqué demasiado este problema en ese momento, solo expliqué brevemente el mecanismo de renderizado de React. Aquí hay un resumen de Señales.

Ventaja

En comparación con React, la granularidad de respuesta del estado del marco basada en Signals es muy buena. Aquí tomamos Solid como ejemplo:

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

const CountingComponent = () => {
  // 创建一个 signal
  const [count, setCount] = createSignal(0);

  // 创建一个 signal
  const [count2] = createSignal(666);

  // 每一秒递增 1
  const interval = setInterval(() => {
    setCount((c) => c + 1);
  }, 1000);

  // 组件销毁时清除定时器
  onCleanup(() => clearInterval(interval));

  return (
    <div>
      <div>
        count: {count()}
        {console.log("count is", count())}
      </div>
      <div>
        count2: {count2()}
        {console.log("count2 is", count2())}
      </div>
    </div>
  );
};

El código anterior solo imprimirá el conteo cuando el conteo cambie, pero no imprimirá los datos del conteo2 en absoluto.

La impresión de la consola se ve así:

  • el recuento es 0
  • cuenta2 es 666
  • contar es 1
  • contar es 2
  • ...

A juzgar por los resultados de la impresión, Solid solo ejecutará la función de renderizado una vez al principio y solo renderizará los nodos DOM modificados posteriormente. Esto es imposible de hacer en React. React se basa en vistas. Los cambios de estado volverán a ejecutar toda la función de renderizado, y React es completamente incapaz de reconocer cómo se usa el estado. Los desarrolladores pueden incluso implementar React a través del siguiente código de volver a renderizar.

const [, forceRender] = useReducer((s) => s + 1, 0);

Además de las actualizaciones detalladas, el modelo mental marco que utiliza Signals también es más simple. La característica más importante es que los desarrolladores no tienen que preocuparse por dónde se define el estado ni dónde se representa el estado correspondiente. Como sigue:

import { createSignal } from "solid-js";

// 把状态从过组件中提取出来
const [count, setCount] = createSignal(0);
const [count2] = createSignal(666);

setInterval(() => {
  setCount((c) => c + 1);
}, 1000);

// 子组件依然可以使用 count 函数
const SubCountingComponent = () => {
  return <div>{count()}</div>;
};

const CountingComponent = () => {
  return (
    <div>
      <div>
        count: {count()}
        {console.log("count is", count())}
      </div>
      <div>
        count2: {count2()}
        {console.log("count2 is", count2())}
      </div>
      <SubCountingComponent />
    </div>
  );
};

El código anterior aún puede ejecutarse normalmente. Porque está impulsado por el Estado. Cuando los desarrolladores usan Signal dentro de un componente, es un estado local, y cuando definen Signal fuera del componente, es un estado global.

Las señales por sí solas no son tan valiosas, pero combinadas con el estado derivado y los efectos secundarios sí lo son. El código se ve así:

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

const [count, setCount] = createSignal(0);

setInterval(() => {
  setCount((c) => c + 1);
}, 1000);

// 计算缓存
const doubleCount = createMemo(() => count() * 2);

// 基于当前缓存
const quadrupleCount = createMemo(() => doubleCount() * 2);

// 副作用
createEffect(() => {
  // 在 count 变化时重新执行 fetch
  fetch(`/api/${count()}`);
});

const CountingComponent = () => {
  // 挂载组件时执行
  onMount(() => {
    console.log("start");
  });

  // 销毁组件时执行
  onCleanup(() => {
    console.log("end");
  });

  return (
    <div>
      <div>Count value is {count()}</div>
      <div>doubleCount value is {doubleCount()}</div>
      <div>quadrupleCount value is {quadrupleCount()}</div>
    </div>
  );
};

Como puede ver en el código anterior, ni el estado derivado ni los efectos secundarios requieren completar dependencias como React, y los efectos secundarios también están separados del ciclo de vida (el código es más fácil de leer).

Mecanismo de implementación

De grano fino, de alto rendimiento y sin limitaciones. Es digno de ser aclamado como el futuro de los marcos front-end. Entonces, ¿cómo se logra exactamente?

Esencialmente, las señales son un contenedor de valor que rastrea las dependencias cuando se accede a ellas y desencadena efectos secundarios cuando se modifican.

Este paradigma basado en tipos subyacentes reactivos no es un concepto particularmente nuevo en el mundo del front-end: se remonta a más de una década con implementaciones como Knockout observables y Meteor Tracker. La API opcional de Vue sigue el mismo principio, excepto que el tipo básico está oculto detrás de las propiedades del objeto. Basándose en este paradigma, Vue2 tiene un rendimiento muy bueno sin necesidad de optimización.

colección de dependencias

React useState devuelve el estado actual y una función de valor establecido, mientras que createSignal de Solid devuelve dos funciones. Ahora mismo:

type useState = (initial: any) => [state, setter];

type createSignal = (initial: any) => [getter, setter];

¿Por qué createSignal necesita pasar el método getter en lugar de pasar directamente el valor de estado correspondiente? Esto se debe a que para que el marco responda, Signal debe recopilar quién está interesado en su valor. El simple hecho de pasar el estado no puede proporcionar ninguna información sobre Signal. El método getter no solo devuelve el valor correspondiente, sino que también crea una suscripción durante la ejecución para recopilar toda la información de dependencia.

Compilación de plantillas

Para garantizar el alto rendimiento del marco de Signals, esta función debe implementarse junto con la compilación de plantillas. Los desarrolladores del marco logran una separación dinámica y estática a través de la compilación de plantillas, y con la recopilación de dependencias, se pueden lograr actualizaciones DOM punto a punto cuando las variables de estado cambiar. Por lo tanto, el marco actual de Signals no utiliza DOM virtual. Vue, que se basa en DOM virtual, actualmente depende del compilador para lograr optimizaciones similares.

Primero echemos un vistazo a la compilación de la plantilla Solid:

const CountingComponent = () => {
  const [count, setCount] = createSignal(0);
  const interval = setInterval(() => {
    setCount((c) => c + 1);
  }, 1000);

  onCleanup(() => clearInterval(interval));
  return <div>Count value is {count()}</div>;
};

Corresponde al código del componente compilado.

const _tmpl$ = /*#__PURE__*/ _$template(`<div>Count value is `);

const CountingComponent = () => {
  const [count, setCount] = createSignal(0);
  const interval = setInterval(() => {
    setCount((c) => c + 1);
  }, 1000);

  onCleanup(() => clearInterval(interval));
  return (() => {
    const _el$ = _tmpl$(),
      _el$2 = _el$.firstChild;
    _$insert(_el$, count, null);
    return _el$;
  })();
};
  • Ejecute la función _tmpl$ para obtener la plantilla estática del componente correspondiente
  • Extraiga la función de recuento en el componente y vincule la función de estado a la posición de la plantilla correspondiente mediante _$insert
  • Al llamar a la función setCount para actualizar, compare el recuento correspondiente y luego modifique los datos correspondientes _el$ correspondientes

otro

Puede echar un vistazo a los marcos principales que utilizan señales:

Sin embargo, parece que es posible que el equipo de React no utilice Signals en este momento.

  • Las señales funcionan bien, pero no son una buena forma de escribir código de interfaz de usuario
  • Planes para mejorar el rendimiento a través del compilador.
  • Se pueden agregar primitivos como Señales

PREACT El autor escribió @preact/signals-react para proporcionar señales para React. Sin embargo, personalmente no recomiendo usarlo en un entorno de producción.

El espacio es limitado, interpretaré el código fuente de @preact/signals-core más adelante .

Referencias

alentar

Si crees que este artículo es bueno, espero que puedas animarme y ayudarme a destacarlo en mi blog de github.

Dirección del blog

El autor del marco de código abierto NanUI pasó a vender acero y el proyecto fue suspendido. La primera lista gratuita en la App Store de Apple es el software pornográfico TypeScript. Acaba de hacerse popular, ¿por qué los grandes empiezan a abandonarlo? Lista de octubre de TIOBE: Java tiene la mayor caída, C# se acerca Java Rust 1.73.0 lanzado Un hombre fue alentado por su novia AI a asesinar a la Reina de Inglaterra y fue sentenciado a nueve años de prisión Qt 6.6 publicado oficialmente Reuters: RISC-V La tecnología se convierte en la clave de la guerra tecnológica entre China y Estados Unidos. Nuevo campo de batalla RISC-V: no controlado por ninguna empresa o país, Lenovo planea lanzar una PC con Android.
{{o.nombre}}
{{m.nombre}}

Supongo que te gusta

Origin my.oschina.net/wsafight/blog/10115779
Recomendado
Clasificación