Svelte 反应性如何在函数内部工作?
Posted
技术标签:
【中文标题】Svelte 反应性如何在函数内部工作?【英文标题】:How does Svelte reactivity work inside functions? 【发布时间】:2020-01-18 02:57:38 【问题描述】:我在 Svelte 的反应性方面存在一些严重问题。我已经隔离了我认为至少是我的主要问题之一。将变量绑定到复选框时,在函数内部而不是外部设置变量时反应性似乎中断。这是预期的行为吗?在那种情况下为什么?预期的工作流程是什么?
示例代码,一个 Svelte 组件:
<script>
let foo = true;
// This assignment works both on the plain text view (Foo: true/false)
// and on the checkbox
// setInterval(() => foo = !foo, 500)
// This assignment works only on the plain text view (Foo: true/false)
// but not for the checkbox
function action()
foo = !foo;
</script>
Foo: foo <br />
Checkbox: <input type="checkbox" bind:checked= foo on:click|preventDefault= action />
Svelte REPL 来看看这个问题的实际效果:https://svelte.dev/repl/73de7d705ab3442786710cd88ea3f625?version=3.12.1
【问题讨论】:
【参考方案1】:最好的解决方案要简单得多,因为双向绑定本身就可以满足您的所有需求。所以,这样做:
<script>
let foo = true;
</script>
Foo: foo <br />
Checkbox: <input type="checkbox" bind:checked= foo />
我知道这个问题已经存在两年了,但我认为它需要更好地结束。
【讨论】:
【参考方案2】:我建议不要使用 preventDefault 取消事件,因为它会停止复选框的默认行为。
因此reactivity
是broken
。如果您将 foo 的重新分配包装在 setTimeout 中,您只会欺骗事件循环并且不会阻止默认值。
因此,如果您想停止事件的传播,请根据 Filip 的建议使用 preventDefault。
<script>
let foo = true;
// This assignment works both on the plain text view (Foo: true/false)
// and on the checkbox
// setInterval(() => foo = !foo, 500)
// This assignment works only on the plain text view (Foo: true/false)
// but not for the checkbox
async function action(e)
e.preventDefault();
setTimeout(() => foo =! foo);
</script>
Foo: foo <br />
Checkbox: <input type="checkbox" bind:checked= foo on:click= action />
【讨论】:
preventDefault 是必需的,因为例如在函数中完成异步操作之前状态不应更改。很遗憾,它并没有解决我的问题,但谢谢。 :) 我已对您的建议进行了答复。以便在异步操作中处理状态更改并阻止默认值 嗯,我尝试在 REPL 中移动 preventDefault 但也无法使其正常工作? svelte.dev/repl/f6fefe4f1656429d980d964c1ff25b53?version=3.12.1 (不同之处在于我在操作中添加了 e:所以 preventDefault() 实际运行)【参考方案3】:似乎您的问题是由bind:
选项引起的。这样做会导致 foo 被更新两次:一次用于“动作”,一次是在绑定启动时在幕后。
只需删除 bind:
即可
<script>
let foo = true;
// This assignment works both on the plain text view (Foo: true/false)
// and on the checkbox
// setInterval(() => foo = !foo, 500)
// This assignment works only on the plain text view (Foo: true/false)
// but not for the checkbox
function action()
setTimeout(() => foo = !foo, 1000);
</script>
Foo: foo <br />
Checkbox: <input type="checkbox" checked= foo on:click|preventDefault= action />
这是有道理的,因为您确实不希望将选中状态双向绑定到 foo。您只希望复选框反映 foo 的值。
【讨论】:
代码示例有效,但诀窍在于 setTimeout()。即使我添加了 bind: back,它也可以工作,只要 foo 声明在该超时内而不是直接在函数第一范围内。【参考方案4】:如果您将变量声明包装在 setTimeout
中而没有任何时间限制(使其默认为 0 并因此尽快运行),您的代码将起作用。
function action()
setTimeout(() =>
foo = !foo;
);
我希望我能解释为什么会这样,但我不能......
【讨论】:
以上是关于Svelte 反应性如何在函数内部工作?的主要内容,如果未能解决你的问题,请参考以下文章