Svelte store assignment 调用默认 writable().set 然后自定义 .set?
Svelte store assignment calls default writable().set and then custom .set?
我有一个带有自定义 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
的值发生变化,并且 then set
将其记录到控制台。为什么(以及如何)发生这种情况,有没有办法在不重新实现的情况下绕过它 writable
?
谢谢!
在您的 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];
}
使用 shorthand 反应式赋值 $<store>
编译成 set_store_value()
调用,这是定义的一个精巧的内部方法 thusly:
export function set_store_value(store, ret, value = ret) {
store.set(value);
return ret;
}
因此,正如您所期望的那样,分配的值实际上传递给您商店的 set
函数。
但是,在上面的JS输出中可以看到,最终返回的值是一个local变量,叫做$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 }); // ''
我希望这种行为是某种乐观的 look-ahead/resolution。
也许 Svelte store contract 中暗示传递给商店的 set
方法的值 必须 实际上相应地修改商店,在这种情况下乐观的解决方法总能产生连贯的结果?
希望 Rich Harris(或其他 Svelte 贡献者)能看到您的问题并提供更明确的答案。
扩展 Thomas Hennes 的精彩分析:
set_store_value(state, $state.a = 1, $state);
此内部调用更新内部存储模型 ($state.a = 1
),而不使用 set
或 update
方法。对我来说,这有点出乎意料,可能是一个小错误。至少,这是我们在设计复杂的自定义商店并希望使用商店简写时需要牢记的事情。
这是预期的行为!暂时忘记商店,并且 - 因为 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
被分配触及后的价值运算符。
我有一个带有自定义 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
的值发生变化,并且 then set
将其记录到控制台。为什么(以及如何)发生这种情况,有没有办法在不重新实现的情况下绕过它 writable
?
谢谢!
在您的 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];
}
使用 shorthand 反应式赋值 $<store>
编译成 set_store_value()
调用,这是定义的一个精巧的内部方法 thusly:
export function set_store_value(store, ret, value = ret) {
store.set(value);
return ret;
}
因此,正如您所期望的那样,分配的值实际上传递给您商店的 set
函数。
但是,在上面的JS输出中可以看到,最终返回的值是一个local变量,叫做$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 }); // ''
我希望这种行为是某种乐观的 look-ahead/resolution。
也许 Svelte store contract 中暗示传递给商店的 set
方法的值 必须 实际上相应地修改商店,在这种情况下乐观的解决方法总能产生连贯的结果?
希望 Rich Harris(或其他 Svelte 贡献者)能看到您的问题并提供更明确的答案。
扩展 Thomas Hennes 的精彩分析:
set_store_value(state, $state.a = 1, $state);
此内部调用更新内部存储模型 ($state.a = 1
),而不使用 set
或 update
方法。对我来说,这有点出乎意料,可能是一个小错误。至少,这是我们在设计复杂的自定义商店并希望使用商店简写时需要牢记的事情。
这是预期的行为!暂时忘记商店,并且 - 因为 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
被分配触及后的价值运算符。