【问题标题】:Why doesn't an array of writables properly update values inside the Svelte component?为什么可写数组不能正确更新 Svelte 组件内的值?
【发布时间】:2020-06-19 17:17:24
【问题描述】:

我有一个父模板 (App.svelte),它创建一个可写数组并将其传递给一个组件 (RedOrBlueOrPurple.svelte)。该组件对项目进行迭代。我想传递一个可写数组(而不是创建一个包含整个对象数组的单个可写数组),因为我想在项目内部发生变化时分别在每个项目上添加subscribe 处理程序。否则,我的订阅处理程序将需要弄清楚哪个项目已更改,这似乎需要更多工作。

在下面的这段代码中,第一个按钮确实有效地改变了紫色属性,因为对update 的调用后面跟着一个refresh,它重置了父值。如果可能的话,我很想避免这个调用,只使用可写作为父母和孩子都理解和可以使用的接口。

另外,我不喜欢模板必须在每个模板上使用 map 来取出商品,获取商店的价值(使用 svelte 内部调用 get_store_value),但我不喜欢知道我将如何使用{#each items as $items...} 否则(我无法弄清楚如何使用$item 在这里)。有没有更优雅的获取价值的方式?

另外,这似乎真的很不幸,当我调用刷新并设置 const 变量时控制台不显示错误这一事实似乎违反了 JS 规则并且仍然可以编译。我知道 Svelte 会在后台注释这个调用以对更改做出反应,但这似乎是错误的。

这里是这个 REPL:https://svelte.dev/repl/84fbae4358494844a79a7f119b084f01?version=3.19.2

<script>
    import { writable } from 'svelte/store';
    import RedOrBlueOrPurple from './RedOrBlueOrPurple.svelte';

    const items = [];
    items.push( writable( { blue: true }));
    items.push( writable( { blue: false, red: true }));
    items.push( writable( { blue: true, red: true }));

const refresh = () => {
    items = items;
};

</script>

<RedOrBlueOrPurple {refresh} {items}/>

<script>
    import { get_store_value } from 'svelte/internal';
    export let items;
    export let refresh;

    const purple = (item, callRefresh) => {
        item.update( i => {
            i.purple = true;
            return i;
        });
        // We only call this for the first button, and if we don't, 
        // the items aren't updated, even though we do call update on
        // the store correctly. 
        if (callRefresh) {
            refresh();
        }
    };
</script>

{#each items.map( item => ({ item, value: get_store_value(item) })) as { item, value}, index }

<h1>
    Item : { index }
</h1>

<div>
RED: { value.red ? "Red" : "Not red"}
</div>
<div>
BLUE: { value.blue ? "Blue" : "Not blue"}
</div>

<div>
PURPLE: { value.purple ? "Purple" : "Not purple"}
</div>

<button on:click={ () => { purple(item, index === 0) } }>Change to purple</button>

{/each}

【问题讨论】:

    标签: javascript svelte svelte-store


    【解决方案1】:

    仅当 svelte 检测到对 items 的分配(您在 #each 中使用)时才会触发屏幕更新。仅仅更新数组的任何项目是不够的。您可以像这样简单地解决它:

    const purple = (item, callRefresh) => {
        item.update( i => {
            i.purple = true;
            return i;
        });
        items = items;  // instead of using the callback, simple reassign items here
    };
    

    【讨论】:

    • 太好了。我仍然觉得在 store 上调用 update 应该足以获得反应,但至少现在我的父母不需要做任何事情。
    【解决方案2】:

    您可以通过使用派生商店来解决这个问题:

    $: values = derived(items, x => x)
    

    所以你的代码会变成:

    App.svelte

    <script>
        import { writable } from 'svelte/store';
        import RedOrBlueOrPurple from './RedOrBlueOrPurple.svelte';
    
        let items = [];
        items.push( writable( { blue: true }));
        items.push( writable( { blue: false, red: true }));
        items.push( writable( { blue: true, red: true }));
    
        const more = () => {
            items = [writable({}), ...items]
        }
    </script>
    
    <!-- another button to ensure new items are processed correctly -->
    <button on:click={more}>More</button>
    
    <RedOrBlueOrPurple {items}/>
    

    RedOrBlueOrPurple.svelte

    <script>
        import { derived } from 'svelte/store'
    
        export let items = [];
    
        $: values = derived(items, x => x)
    
        const purple = (item, callRefresh) => {
            item.update(i => ({ ...i, purple: true }))
        };
    </script>
    
    {#each $values as value, index}
        <h1>Item: {index}</h1>
        <pre>{JSON.stringify(value)}</pre>
        <button on:click={() => {purple(items[index])}}>Change to purple</button>
    {/each}
    

    Updated REPL

    注意

    不要:

    import { get_store_value } from 'svelte/internal';
    

    有一个等效的公共 API(请参阅 docs):

    import { get } from 'svelte/store'
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-07-25
      • 1970-01-01
      • 1970-01-01
      • 2021-10-03
      • 1970-01-01
      • 2021-08-20
      • 1970-01-01
      相关资源
      最近更新 更多