6

相关 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

谢谢!

4

3 回答 3

4

这是预期的行为!暂时忘记商店,并且 - 因为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}

...正是您所期望的。

当我们用 替换pojo$state,我们仍在分配(或改变)一个具有相同反应特性的局部变量。唯一的区别是我们也在调用state.set. 通常,这会导致存储值发生变化,并反映给其订阅者,但由于您的自定义存储不这样做,所以我们留下了最后一次$state被赋值运算符触及之后的值。

于 2020-07-23T18:48:14.147 回答
3

在 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 贡献者)能看到您的问题并提供更明确的答案。

于 2020-07-22T11:59:44.843 回答
1

扩展 Thomas Hennes 的伟大分析:

set_store_value(state, $state.a = 1, $state);

此内部调用更新内部存储模型 ( $state.a = 1),而不使用setorupdate方法。对我来说,这有点出乎意料,可能是一个苗条的错误。至少,当我们设计复杂的定制商店并想要使用商店速记时,我们需要牢记这一点。

于 2020-07-22T12:14:03.983 回答