免责声明:我在任何方面都不是一个固体。 ”。
介绍
尽管我开始学习 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)
在上面的示例中:
-
此功能是一个可靠的“组件”,我们称其为“喜欢”组件。固体知道如何将此功能转换为引擎盖下的组件。我们只需要从函数返回一些HTML(基本上不是“正常的HTML”,它是“ JSX”,它在创建DOM之前会由编译器翻译成JavaScript,但我们不需要关心它)。
-
我们可以使用
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次,世界!
因此,让我们解决这个主要问题。为了修复它,我们需要跳过效果的第一个触发器(传递给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)
如您在上面的摘要中所见:
-
on
函数的第一个参数是我们希望明确依赖的信号。 -
第二个参数是效果本身,但是,信号的值传递给了它(不是信号本身,所以我们使用
c
而不是c()
使用它)。
现在它可以按照我们的预期方式工作!
用过的钩子
现在回到我们手头的最初目标!这是我们要如何使用此钩子的一个例子:
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)
createEffect
和on
不再需要!
如果您想知道第一个渲染中的clearTimeout
会发生什么:clearTimeout
的API可以使用undefined
传递给它,只是忽略了它。同样,如果您想知道为什么我们需要onCleanup
调用,那是因为上次设置了计时器,则组件可能会卸载而不会清理计时器,这可能会导致错误。 (此示例还显示了onCleanup
如何不依赖createEffect
,如果您来自React,这可能与您使用的相反。)
奖金:固体原始图书馆
尽管上述解决方案 的测试还不够,正如我最初说的那样,我的经验不足以保证上述解决方案的质量。但是现在担心,值得庆幸的是,Solid的社区非常有帮助,他们已经为这种频繁的需求提供了像React的Usehooks-Ts这样的图书馆,他们称其为“固体基础”。因此,如果您想要使用Solid进行反击的战斗测试解决方案,我建议您使用此库中的debounce primitive。只需像我们在上面使用自己的debounce
钩子一样安装,导入和使用它!如果他们的工作使您作为开发人员的生活更加容易。
感谢您阅读本文,非常欢迎您建议在下面的评论部分中提出任何修复和改进。
快乐的固体编码。 ð
嘿,您还邀请您加入我们的小而刚起步的ð¥ð£Discord社区,称为 til (代表“ 今天 - 我学习“)在网络编程领域,我们在分享彼此之间学到的东西的位置。使用此link加入。