英文:
Variable is not changed if I update it in closure
问题
<script>
let count = { value: 0 };
const increase = (data) => {
console.log(data);
data = { ...data, value: data.value + 1 };
}
const increment = () => increase(count);
</script>
<button on:click={increment}>
Clicked {count.value}
{count.value === 1 ? 'time' : 'times'}
</button>
英文:
<script>
let count = {value:0};
const increase = (data)=>{
console.log(data);
data = {...data,value: data.value+1};
}
const increment = ()=>increase(count);
</script>
<button on:click={increment}>
Clicked {count.value}
{count.value === 1 ? 'time' : 'times'}
</button>
I simplified my problem to this code. I have a closure function that accepts an object and tries to update it. At first, I used the 'count' variable as a number but I thought it will not pass the reference so I changed it to an object. But either ways, the count is not change.
答案1
得分: 1
You're just re-assigning the data variable, but to change the count state you need to assign the latest object to the count variable.
<script>
let count = { value: 0 };
const increment = () => {
count = { ...count, value: count.value + 1 }
}
</script>
<button on:click={increment}>
Clicked {count.value}
{count.value === 1 ? 'time' : 'times'}
</button>
英文:
You're just re-assigning the data variable, but to change the count state you need to assign the latest object to the count variable.
<script>
let count = { value: 0 };
const increment = () => {
count = { ...count, value: count.value + 1 }
}
</script>
<button on:click={increment}>
Clicked {count.value}
{count.value === 1 ? 'time' : 'times'}
</button>
答案2
得分: 1
以下是翻译好的内容:
有两个问题与您的代码有关:
data = {...data, value: data.value + 1};
通过这行代码,您正在将一个新对象重新分配给_data_,从而删除了之前传递的_data_对象的引用。因此,在这种情况下,'count' 不会更改。(您可以看到,因为在连续点击时,日志中始终显示 value: 0
。)
如果您将其更改为
data.value += 1;
您将修改传递的对象,因为在这里您保持了引用的完整性。使用此代码,连续点击将显示_count_已更改。
然而,标记不会更新,因为 Svelte 的工作方式是,只有在变量上看到分配时,它才会更新,否则它无法(或者至少没有性能好的方法)检测到对象的更改。因此,您必须在某处使用 count = ...
,以便 Svelte 知道 count 已经更新。
您可以尝试通过添加以下内容来验证:
<button on:click={() => count = count}>刷新</button>
您将看到,单击此按钮将更新UI。
一种解决方法可能是重写 increment
为:
const increment = () => {
increase(count);
count = count;
}
或者,重写 increase
以返回数据对象并直接重新分配:
const increment = () => count = increase(count);
对于您在答案评论中的评论,请注意,您还可以定义内联函数:
<button on:click={() => count1 = increase(count1)}>
点击 {count.value} {count1.value === 1 ? '次' : '次数'}
</button>
<button on:click={() => count2 = increase(count2)}>
点击 {count.value} {count2.value === 1 ? '次' : '次数'}
</button>
<button on:click={() => count3 = increase(count3)}>
点击 {count.value} {count3.value === 1 ? '次' : '次数'}
</button>
英文:
There are two problems with your code
data = {...data,value: data.value+1};
With this line you are re-assigning a new object to data, removing the reference to the data object you passed in before. So in this case 'count' doesn't change. (You can see this because in successive clicks you keep getting value: 0
in the logs.
If you change this to
data.value += 1;
You will be modifying the object you passed in because here you do keep the reference intact. With this code, successive clicks will show that count has changed.
The markup however will not update because how Svelte works, it will only update if it sees an assignment on the variable, otherwise it has no way (or at least not a performant way) to detect changes to objects. So you have to have somewhere count = ...
for Svelte to know that count has updated.
You can try this by adding
<button on:click={() => count = count}>Refresh</button>
You will see that when clicking this button it will update the UI.
A solution might be to rewrite increment to
const increment = () => {
increase(count);
count = count;
}
Or alternatively, rewrite increase
to return the data object and reassign directly
const increment = () => count = increase(count);
edit for your comment on an answer
Notice that you can also define an inline function:
<button on:click={() => count1 = increase(count1)}>
Clicked {count.value} {count1.value === 1 ? 'time' : 'times'}
</button>
<button on:click={() => count2 = increase(count2)}>
Clicked {count.value} {count2.value === 1 ? 'time' : 'times'}
</button>
<button on:click={() => count3 = increase(count3)}>
Clicked {count.value} {count3.value === 1 ? 'time' : 'times'}
</button>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论