让我们快速学习solid.js,创建一个二手钩钩
#javascript #网络开发人员 #初学者 #solidjs

免责声明:我在任何方面都不是一个固体。 ”。

介绍

尽管我开始学习 solid.js 两天前,但我觉得这使我非常有生产力。我尝试将其作为第一个个人练习而尝试做的一件事是创建一个“抽屉”(抽屉是那些从一侧进入页面的菜单,以防您不知道)。

我写了几行非常易于理解的(阅读“可爱”)代码,然后瞧,它起作用了!

在这一点上,我对自己开始的旅程感到非常满意,所以我决定进行第二次练习:使抽屉变得“不那么疯狂”!即,我不希望它扩展“只是在鼠标开始徘徊”时,我希望它“等待”一段时间(延迟),然后让用户下定决心,他们是否真的希望抽屉到开放与否。所以我需要一个辩论者!(如果您不知道是什么,请不要担心)。

最终恰好是一个有趣的练习,它教会了我更多的Solid API,所以我决定与其他同伴学习者(您!)分享它。不用担心,如果您不知道任何固体。

什么是辩论?

对我来说,拒绝意味着“不跳入结论” 。一个实用的示例,说明辩论者何时有用是,何时用户将字母键入搜索框,并且您想“触发搜索作为用户类型”,您认为这是很棒的UX,用户没有必须单击/点击放大镜(搜索)按钮,但是,这个好主意有一个问题,用户类型的每个字母都会呼叫您的后端...这很浪费。实际上,它甚至可能是“不良UX”,假设搜索框在用户类型时立即对每个字母做出反应,他们可能会觉得搜索框是疯狂的开发人员制作的!

solid.js快速启动教程

反应性

UI框架的一般思想是使视图自动反应对“数据状态”(又称“状态”)的更改。与在此处和那里使用一堆事件侦听器相比,这使其更容易编写和推理UI代码。

信号

实心为状态使用术语“信号”(数据)。当然,这可能不是信号的精确定义,但它对一开始就足够了。让我们继续以代码来进行谈话(希望不便宜!):

function Likes() {
  const [likeCount, setLikeCount] = createSignal(0);
  return (
    <button
      onClick={function like() {
        setLikeCount(likeCount() + 1);
      }}
    >
      {likeCount()} likes
    </button>
  );
}

(游乐场:https://playground.solidjs.com/anonymous/20a27607-7aed-4c34-9249-e09580131742

在上面的示例中:

  1. 此功能是一个可靠的“组件”,我们称其为“喜欢”组件。固体知道如何将此功能转换为引擎盖下的组件。我们只需要从函数返回一些HTML(基本上不是“正常的HTML”,它是“ JSX”,它在创建DOM之前会由编译器翻译成JavaScript,但我们不需要关心它)。

  2. 我们可以使用createSignal函数为我们的数据制作“信号”,然后通过“调用”它们来使用JSX中的信号(例如,{ likeCount() } 注意:必须将其包装在卷曲中由于JSX的工作原理。)。这将使我们的视图“反应”对likeCount,并且每当更改此数据时,使用它(带有调用)的所有事物也将被更新。
    我是故意说的所有“事情”,因为依赖者不一定是JSX,它甚至可以是另一个JavaScript变量,也可以是效果(稍后再介绍)。例如,假设我们希望按钮的背景颜色达到3:
    时,按钮的背景颜色变为绿色

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

function Likes() {
  const [likeCount, setLikeCount] = createSignal(0);
  let likesColor = () => likeCount() >= 3 ? "limegreen" : ""; // <-- The value of the likesColor depends on the value of the likeCount signal, and gets updated whenever likeCount changes. likesColor is also known as a "derived signal".

  return (
    <button
      onClick={function like() {
        setLikeCount(likeCount() + 1);
      }}
      style={{ "background-color": likesColor() }}
    >
      {likeCount()} likes
    </button>
  );
}

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

(游乐场:https://playground.solidjs.com/anonymous/b57f28bb-053b-4d4b-9002-073393a11f1a

效果

现在说,每当单击“类似”按钮时,我们都想向世界大声喊叫!对于这样的事情,我们需要“跟踪信号”,这称为“效果”。

createEffect(() => {
  console.log(`I Was Liked ${likeCount()} times, World!`);
});

(游乐场:https://playground.solidjs.com/anonymous/afaae217-4c65-45e2-a88b-a1f0fb666053

ah ... 它有点有效吗?,但这很la脚!当我们根本不喜欢时,它甚至在第一个渲染上大喊!

我很喜欢0次,世界!

Funny GIF indicating, Nah, no way. A man shaking his head like it's a ball of meat.

因此,让我们解决这个主要问题。为了修复它,我们需要跳过效果的第一个触发器(传递给createEffect的功能),为此,我们需要将效果包裹在on中。这不是on函数的主要目的,而是使效果显式依赖性的一种手段。 (有时我们会有信号,即我们不希望它们更改以重新触发效果。)但是,它与我们的用例无关,我们想从中使用的只是我们的选项对象可以传递给它,这使我们可以跳过第一个触发器:

  createEffect(on(likeCount, (c) => {
    console.log(`I Was Liked ${c} times, World!`);
  }, { defer: true }));

(游乐场:https://playground.solidjs.com/anonymous/1a15305d-2620-4aad-9b7f-ee1e633c002b
如您在上面的摘要中所见:

  1. on函数的第一个参数是我们希望明确依赖的信号。

  2. 第二个参数是效果本身,但是,信号的值传递给了它(不是信号本身,所以我们使用c而不是c()使用它)。

现在它可以按照我们的预期方式工作!

High Five Lets Go GIF

用过的钩子

现在回到我们手头的最初目标!这是我们要如何使用此钩子的一个例子:

const [isOpen, setIsOpen] = createSignal(false);
const isOpenDebounced = useDebounce(isOpen, 400);
// A 400 milliseconds delay to let the user make up their mind,
// or regret it (usually this value is between 400 to 600).

让我们将其编码并希望到现在为止,它将以一种更熟悉的语言与您交谈:

function useDebounce(signal, delay) {
  const [debouncedSignal, setDebouncedSignal] = createSignal(signal());
  let timerHandle;
  createEffect(
    on(signal, (s) => {
      timerHandle = setTimeout(() => {
        setDebouncedSignal(s);
      }, delay);
      onCleanup(() => clearTimeout(timerHandle));
    })
  );
  return debouncedSignal;
}

(游乐场:https://playground.solidjs.com/anonymous/7c8c8d82-502b-4a31-ab96-2cb45a6e705a

如果您还不理解,那是您自己的错,重新阅读所有内容,只是开玩笑。它的要旨是,我们定义了一种效果,取决于我们要签出的信号,因此,每当重置信号时,效果重新触发,onCleanup也将清除先前设置的计时器。

上面的解决方案有一个很大的缺点,必须使用equals: false选项启动传递的状态,以便createEefect即使以相同的值设置了状态,也会重新触发!

  const [likeCount, setLikeCount] = createSignal(0, { equals: false });

当然不是理想的。

更固体解决方案!

更好的(更好ð)用过的bounce的实现esvounation bebounation bebounate bebounate bebounte bebounte bebounte beatser bealde2(不是getter),例如setLikeCount,而不是likeCount(在上面的喜欢的组件示例中)。该解决方案不仅更容易,更可读,而且不需要设置{ equals: false }选项,而且还证明了固体的距离。

function useDebounce(signalSetter, delay) {
  let timerHandle;
  function debouncedSignalSetter(value) {
    clearTimeout(timerHandle);
    timerHandle = setTimeout(() => signalSetter(value), delay);
  }
  onCleanup(() => clearInterval(timerHandle));
  return debouncedSignalSetter;
}

(游乐场:https://playground.solidjs.com/anonymous/0850d269-ca93-4a6d-9607-ca8c2aa2f0cb

createEffecton不再需要!

如果您想知道第一个渲染中的clearTimeout会发生什么:clearTimeout的API可以使用undefined传递给它,只是忽略了它。同样,如果您想知道为什么我们需要onCleanup调用,那是因为上次设置了计时器,则组件可能会卸载而不会清理计时器,这可能会导致错误。 (此示例还显示了onCleanup如何不依赖createEffect,如果您来自React,这可能与您使用的相反。)

这是最终结果:
Preview of the final result

奖金:固体原始图书馆

尽管上述解决方案 的测试还不够,正如我最初说的那样,我的经验不足以保证上述解决方案的质量。但是现在担心,值得庆幸的是,Solid的社区非常有帮助,他们已经为这种频繁的需求提供了像React的Usehooks-Ts这样的图书馆,他们称其为“固体基础”。因此,如果您想要使用Solid进行反击的战斗测试解决方案,我建议您使用此库中的debounce primitive。只需像我们在上面使用自己的debounce钩子一样安装,导入和使用它!如果他们的工作使您作为开发人员的生活更加容易。

,请不要忘记给他们一个明星。

感谢您阅读本文,非常欢迎您建议在下面的评论部分中提出任何修复和改进。

快乐的固体编码。 ð


嘿,您还邀请您加入我们的小而刚起步的ð¥ð£Discord社区,称为 til (代表“ 今天 - 我学习“)在网络编程领域,我们在分享彼此之间学到的东西的位置。使用此link加入。