固体,反应和反应性系统比较
#javascript #react #vue #solidjs

多年来从事许多项目,我使用了多个JavaScript UI框架。反应,vue和现在solid.js是我与之合作并最喜欢的框架。

最近,尤其是在使用solid.js时,我开始注意到并欣赏小细节,例如每个框架的反应性系统如何有所不同。在框架之间跳跃时要记住这是一件重要的事情,因为即使API保持越来越相似,该框架如何在影响性能,软件体系结构以及您对应用程序的看法下的工作方式。

事情是了解框架的反应性系统的全部程度需要时间,需要深入了解其架构。这很多 - 尤其是在使用多个框架时。这就是为什么我想简化这些概念并为您提供足够好的起点,以便您俩都了解主要差异,并且有一个可靠的切入点,可以更深入地探索这个话题。 p>

反应性系统

如果您只使用过或专注于单个框架上的激光,那么您可能没有考虑过其反应性系统或渲染模型过多,尤其是与其他框架相比。如何创建和管理组件状态,触发重新渲染的是什么,UI的哪些部分,虚拟DOM的内部工作以及它们如何影响性能 - 这些都是您通常不考虑的问题构建UI时。但是,有时候值得退后一步,考虑这些事情如何影响您的整个代码库。

反应

在React中,当使用带有钩子的功能组件时,您的整个组件函数就是在每个重新渲染上执行的内容。看看这个示例:

import React, { useState, useEffect } from "react";

const Example = () => {
  const [count, setCount] = useState(0);
  const [someData, setSomeData] = useState(0);

  console.log("re-render");

  useEffect(() => {
    console.log(`You clicked ${count} times`);
  }, [count]);
  useEffect(() => {
    setInterval(() => {
      setSomeData(Math.random());
    }, 1000);
  }, []);

  return (
    <div>
      You clicked {count} times
      <button
        onClick={() => {
          setCount(count + 1);
          console.log(`Count not updated here yet: ${count}`);
        }}
      >
        Click me
      </button>
    </div>
  );
};

由于整个组件函数在每个重新渲染上都重新运行,因此您使用React钩子来定义组件的状态(useState()),以及过滤掉应该的代码仅在更新特定状态属性时运行(useEffect())。这是考虑这里重新订阅器的最简单方法 - 默认情况下运行,您使用钩子来滤除不应该的内容。通过设计。

这里要注意的其他几件事:

  • 即使在视图中使用的值不使用,更新someData(间隔)触发了重新呈现。现在,由于React的工作方式,需要将值保持最新状态,并且由于Virtual Dom,将不执行DOM操作。但是,这仍然是一种重新渲染,在您需要牢记的复杂组件中可能会付出高昂的代价。使用useRef()someData更改为ref将是这里的解决方案。
  • 您只能确保在useEffect()回调中重新渲染后更新了countsetCount()之后的console.log()仍将显示旧值。当您有其他方法可以访问新值或将您的心理模型改编成反应的工作方式时,这并不是问题。如果您是新手做出反应的,或者您不断在不同的框架之间切换,或者在具有复杂事件处理程序的复杂组件上工作 - 这可能是一个问题。如果您要同时更新组件以及立即具有最新值,则可能必须将useState()useRef()相结合。
  • 与其他框架相比,与其他框架相比,这很重要但也很脱颖替代)。

进行战斗,这些问题和其他问题反应建立的钩子规则,并建议将您的代码分为较小的组件。组件及其状态越细,每个重新渲染的电势越小。

Vue

这是VUE 3的同等示例(注意:即使在Vue中不太受欢迎,我使用JSX与其他框架进行了更紧密的视觉比较):

import { defineComponent, ref, watchEffect, onMounted } from "vue";

const Example = defineComponent({
  setup() {
    const count = ref(0);
    const someData = ref(0);
    const onClick = () => {
      count.value = count.value + 1;
      console.log(`Count updated here already: ${count.value}`);
    };

    watchEffect(() => {
      console.log(`You clicked ${count.value} times`);
    });
    onMounted(() => {
      setInterval(() => {
        someData.value = Math.random();
      }, 1000);
    });

    return () => {
      console.log("re-render");

      return (
        <div>
          You clicked {count.value} times
          <button onClick={onClick}>Click me</button>
        </div>
      );
    };
  },
});

在VUE中,每个组件都有一个输入setup()函数。在这里,您使用组合API来设置组件的逻辑,最后返回渲染函数。您会看到仅运行一次的差异以及在每个重新渲染中运行的内容之间的区别。如果您想在某些状态属性更改时运行一块代码,则必须使用观察者将其过滤到更新周期中,而不是在React中过滤。

最重要的是,VUE的反应性系统有一些优势。首先,Vue确实提供了像onMounted()这样的实际生命周期钩子。最重要的是,setup()函数本身是任何不需要组件的逻辑的绝佳切入点。

其次,由于基于JS代理的反应性对象和参考,VUE可以自动检测需要何时需要触发某些效果或重新渲染。因此,您不需要在watchEffect()中提供明确的依赖项(尽管可以使用watch()),而在间隔中设置someData ref会不会触发重新渲染,因为它在视图中未使用。 。

最后,在更新参考时,您可以确定,当您再次读取值时,它已经更改。请记住,该变化触发的重新渲染可能还没有发生,并且UI并未最新。

在框架的虚拟DOM和其他部分上进行了大量优化,Vue的性能与React和可以说是更好的开发体验相比的性能要好得多。 setup()功能为您的组件提供了一个很好的起点,而不必担心过多的重新租户,而Coption API提供了与React Hooks类似的人体工程学。

坚硬的

对我来说,固体通常感觉就像是最好的反应和vue合并。但是,这种思维方式并没有给我完整的框架图片。一旦超越了基本组件,您很快就会发现固体与其他框架大不相同。与Solid合作时,您将不得不忘记您从其他框架中学到的有关组件和反应性的知识。

考虑以下示例:

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

const Example = () => {
  const [count, setCount] = createSignal(0);
  const [someData, setSomeData] = createSignal(0);

  createEffect(() => {
    console.log(`You clicked ${count()} times`);
  });

  onMount(() => {
    setInterval(() => {
      setSomeData(Math.random());
    }, 1000);
  });

  return (
    <div>
      You clicked {count()} times
      <button
        onClick={() => {
          setCount(count() + 1);
          console.log(`Count updated here already: ${count()}`);
        }}
      >
        Click me
      </button>
    </div>
  );
};

在solid.js组件中只有组织代码。这就是为什么仅运行一次组件函数。它类似于React中的组件函数,具有VUE的setup()函数的属性。但是,一旦运行,该组件就会消失,而剩下的就是JSX元素,反应性原语和效果。这与例如vue,每个组件都有一个可以访问的实例。尽管如此,Solid确实提供了一些生命周期钩,例如onMount(),但它们更专注于反应范围,而不是组件的实际生命周期,例如在Vue中。

固体的另一个重要部分是其细粒度的反应性系统。尽管API似乎与钩子的反应相似,但下面完全不同。固体反应性建立在自动跟踪以适当触发效果和UI更新的信号上。因此,与Vue类似,您不需要将明确的依赖项传递给createEffect()(即使您可以使用on()),而更新不在视图中的数据(例如someData)也不会触发UI更新。

实心是三个没有虚拟DOM的唯一框架。得益于细粒度的反应性和编译器优化,Solid能够同步更新UI的正确部分。这会导致表现出色的性能,并向您保证您的UI始终是最新的。因此,调用setCount()函数后,您可以确定该值和UI都已更新。

结论

您可以看到,即使框架在外部似乎相似,许多根本的差异使得或打破了性能和开发人员的经验。

就个人而言,在过去的几年中,Solid一直是我的最爱。由于其最佳性能,反应性系统和API,这是一种发展的经验。这就是为什么它可以为这个博客,Vrite Landing页面提供动力,并很快 - Vrite本身。如果您感兴趣,请牢固看!