相关REPL
我有一个简单的可写存储,带有自定义set
方法:
import { writable } from 'svelte/store';
function createState() {
const {subscribe, set, update} = writable({a: 0, b: 0});
return {
subscribe,
set: (newState) => {
console.log(newState);
// set(newState); // I would expect `state` to be unchanged without this
}
};
};
export const state = createState();
当我调用state.set(<some new value>)
时,新值会记录到控制台中,而state
的值实际上不会更改。这就是我所期望的
但是,如果我分配$state = <some new value>
,则state
的值会更改,则set
会将其记录到控制台。为什么(以及如何(发生这种情况,有没有一种方法可以绕过它而不重新实现writable
?
谢谢!
这是预期行为!暂时忘记存储,并且——由于state.set
在您的示例中是一个noop——删除这一行:
<script>
// import { state } from "./stores.js";
let pojo = { a: 0, b: 0 };
pojo.a = 1;
pojo = {d: 0};
//state.set({c: 0}); // no effect, as expected
</script>
<h1>state: {JSON.stringify(pojo)}</h1>
结果。。。
state: {"d":0}
。。。正是你所期望的。
当我们用$state
替换pojo
时,我们仍然在分配(或突变(一个具有相同反应特性的局部变量。唯一的区别是,我们也调用state.set
。通常情况下,这会导致存储值发生变化,并反映给其订阅者,但由于您的自定义存储不会这样做,因此我们只剩下最后一次赋值运算符触摸$state
之后的值。
在REPL的JS输出中,您可以看到以下内容:
function instance($$self, $$props, $$invalidate) {
let $state;
component_subscribe($$self, state, $$value => $$invalidate(0, $state = $$value));
set_store_value(state, $state.a = 1, $state); // changes the value of state?!
set_store_value(state, $state = { d: 0 }); // ''
state.set({ c: 0 }); // no effect, as expected
return [$state];
}
使用简写的反应式分配$<store>
编译成set_store_value()
调用,这是一个如此定义的苗条内部方法:
export function set_store_value(store, ret, value = ret) {
store.set(value);
return ret;
}
因此,正如您所期望的那样,分配的值实际上被传递给了商店的set
函数。
但是,您可以在上面的JS输出中看到,最终返回的值是一个名为$state
的局部变量(这里的$
符号是,而不是反应修饰符,只是名称的一部分(。在这些set_store_value()
调用过程中,您可以看到这个局部变量被分配了与传递给商店的set
方法的值相同的值(事实上,局部变量被指定了该值,然后自身被传递给set_store_value()
方法(:
set_store_value(state, $state.a = 1, $state); // changes the value of state?!
set_store_value(state, $state = { d: 0 }); // ''
我希望这种行为是某种乐观的展望/解决方案。
也许Svelte商店合同中暗示,传递给商店的set
方法的值实际上必须相应地修改商店,在这种情况下,乐观解析方法总是会产生一致的结果?
希望Rich Harris(或另一位Svelte撰稿人(能看到你的问题,并提供更明确的答案。
扩展Thomas Hennes的伟大分析:
set_store_value(state, $state.a = 1, $state);
该内部调用在不使用set
或update
方法的情况下更新内部存储模型($state.a = 1
(。对我来说,这有点出乎意料,可能是一个苗条的bug。至少,当我们设计复杂的定制商店并想使用商店人手不足时,我们需要记住这一点。