Fyg*_*ygo 4 javascript svelte svelte-3
我在这里有点困惑,不幸的是我无法在 svelte 的不和谐频道上找到任何解决方案,所以我走了......
我有一个相当基本的两个类的例子,让它们是App
和Comp
。
App
创建一个Comp
实例,然后value
在单击按钮后更新此实例。
Comp 实例应该将此值设置为不同的变量 ( inputValue
) 并且在更改该变量时它应该触发validate(inputValue)
它是反应性的。这是一个 REPL:https ://svelte.dev/repl/1df2eb0e67b240e9b1449e52fb26eb14 ? version = 3.25.1
App.svelte:
<script>
import Comp from './Comp.svelte';
let value = 'now: ' + Date.now();
function clickHandler(e) {
value = 'now ' + Date.now();
}
</script>
<Comp
bind:value={value}
/>
<button type="button" on:click={clickHandler}>change value</button>
Run Code Online (Sandbox Code Playgroud)
Comp.svelte:
<script>
import { onMount } from 'svelte';
export let value;
let rendered = false;
let inputValue = '';
$: validate(inputValue); // This doesn't execute. Why?
function validate(val) {
console.log('validation:', val);
}
onMount(() => {
rendered = true;
});
$: if (rendered) {
updateInputValue(value);
}
function updateInputValue(val) {
console.log('updateInputValue called!');
if (!value) {
inputValue = '';
}
else {
inputValue = value;
}
}
</script>
<input type="text" bind:value={inputValue}>
Run Code Online (Sandbox Code Playgroud)
因此,一旦值发生变化:
if (rendered) {...}
条件称为updateInputValue
被调用并被inputValue
改变。HTML input 元素更新为此值。validate(inputValue)
永远不会对这种变化做出反应 -为什么?如果我updateInputValue
在反应if (rendered)
条件中省略对函数的额外调用并将updateInputValue
函数体的代码直接放在条件中,validate(inputValue)
则被正确触发,即:
// works like this
$: if (rendered) {
if (!value) {
inputValue = '';
}
else {
inputValue = value;
}
}
Run Code Online (Sandbox Code Playgroud)
那么为什么在函数中更新时它不起作用呢?
@johanchopin 的回答揭示了这个问题。
你可以阅读我的博客文章,对反应式声明的工作原理进行稍微深入的解释,这里是 tl;dr:
反应式声明是批量执行的。
svelte 批量处理所有更改以在下一个更新周期更新它们,并且在更新 DOM 之前,它会执行响应式声明来更新响应式变量。
反应式声明按照它们的依赖顺序执行。
反应式声明是批量执行的,每个声明执行一次。一些声明相互依赖,例如:
let count = 0;
$: double = count * 2;
$: quadruple = double * 2;
Run Code Online (Sandbox Code Playgroud)
在这种情况下,quadruple
取决于double
。因此,无论您的反应性声明的顺序如何,无论是$: double = count * 2;
在之前$: quadruple = double * 2
还是相反,前者都应该并且将在后者之前执行。
Svelte将按依赖顺序对声明进行排序。
在相互之间没有依赖关系的情况下:
$: validate(inputValue);
$: if (rendered) updateInputValue(value);
Run Code Online (Sandbox Code Playgroud)
第一条语句取决于validate
and inputValue
,第二条语句取决于rendered
, updateInputValue
and value
,声明按原样保留。
现在,了解了反应式声明的这 2 种行为,让我们来看看您的REPL。
当您更改inputValue
,rendered
或者value
,将斯维尔特批次的变化,并开始一个新的更新周期。
在更新 DOM 之前,Svelte 将一次性执行所有反应式声明。
因为validate(inputValue);
andif (rendered) updateInputValue(value);
语句之间没有依赖关系(如前所述),它们将按顺序执行。
如果更改rendered
or value
only,则第 1 条语句 ( validate(inputValue)
) 不会执行,同样,如果更改inputValue
,if (rendered) updateInputValue(value)
则不会执行第 2 条语句 ( )。
现在,在updateInputValue
您更改 的值时inputValue
,但因为我们已经处于更新周期中,所以我们不会开始一个新的。
这通常不是问题,因为如果我们按依赖顺序对反应式声明进行排序,更新依赖变量的语句将在依赖变量的语句之前执行。
因此,知道出了什么问题,您可以寻求一些“解决方案”。
请参阅此REPL 中对反应性声明进行排序的区别
因此,将您的 REPL 更改为:
$: if (rendered) {
updateInputValue(value);
}
$: validate(inputValue);
Run Code Online (Sandbox Code Playgroud)
$: validate(inputValue);
$: if (rendered) {
inputValue = updateInputValue(value);
}
function updateInputValue(val) {
console.log('updateInputValue called!');
if (!value) {
return '';
}
else {
return value;
}
}
Run Code Online (Sandbox Code Playgroud)
真的很奇怪(我无法真正解释它),但是如果您将反应式语句放在$: validate(inputValue);
函数updateInputValue
声明之后,它就会按预期工作:
<script>
import { onMount } from 'svelte';
export let value;
let rendered = false;
let inputValue = '';
function validate(val) {
console.log('validation:', val);
}
onMount(() => {
rendered = true;
});
$: if (rendered) {
updateInputValue(value);
}
function updateInputValue(val) {
console.log('updateInputValue called!');
if (!value) {
inputValue = '';
}
else {
inputValue = value;
}
}
$: validate(inputValue);
</script>
Run Code Online (Sandbox Code Playgroud)
检查这个REPL。
归档时间: |
|
查看次数: |
2634 次 |
最近记录: |