编辑类型数组的可写对象时,Svelte UI 未正确更新

Svelte UI not properly updated when Writable of Type Array is edited

我目前正在为一家赛艇俱乐部开发船员创作者,以了解背景。

包含数组的Writable是这样声明的


import { writable, Writable } from 'svelte/store';
import type { CrewMember } from '../types';

export default writable<Writable<CrewMember>[]>([], () => {
    console.log('Subscriber Detected ON CREW MEMBERS');

    return () => console.log('No More Subscribers ON CREW MEMBERS');
});

这就是我从数组中删除特定项目的方式

members.update((currentList) => {
    let tmp = currentList.filter((val) => {
        if (val != mem) return true;
    });

    return tmp;
});

其中 mem 是传递给删除函数的 Writable<CrewMember>。我也尝试过通过 ID 删除,但目前也没有用。

代码从列表中删除项目很好,但是它没有正确更新 UI,总是删除 table 的最后一项而不是删除的项目,这确实得到由于它们被推送到数据库而刷新页面时已修复。

会不会是因为我用的是 Writable<Writable<CrewMember>[]> 因为连我都知道这听起来很该死。

以下是导致问题的整个代码块

<script lang="ts">
    import { onDestroy, onMount } from 'svelte';
    import { get } from 'svelte/store';
    import type { Writable } from 'svelte/store';
    import type { CrewMember } from '../../types';

    import CrewMemberListItem from './CrewMemberListItem.svelte';

    export let members: Writable<Writable<CrewMember>[]>;
    export let pushToBuffer: { (mem: Writable<CrewMember>): void };

    let unsubscribe: { (): void };

    function deleteMember(mem: Writable<CrewMember>) {
        let member = get(mem);

        if (!confirm(`Are you sure that you want to delete ${member.name}?`))
            return;

        member.delete().then(() => {
            members.update((currentList) =>
                currentList.filter((val) => val != mem)
            );
        });
    }

    onMount(() => {
        unsubscribe = members.subscribe(
            (_updatedValue: Writable<CrewMember>[]) => {
                // internalMembersBuffer = updatedValue;
            }
        );
    });

    onDestroy(() => {
        unsubscribe();
    });
</script>

<table id="member-editor-list">
    <tr class="header">
        <th>Gender</th>
        <th>Age Group</th>
        <th class="left">Name</th>
        <th>Actions</th>
    </tr>

    {#each $members as member}
        <CrewMemberListItem
            {member}
            {pushToBuffer}
            deleteFunction={deleteMember}
        />
    {/each}
</table>

为了简单起见,删除了 css

感谢@pilchard 提醒我 keyed each 块的存在。这才是我应该一直使用的。

无需更改逻辑,但每个块现在应如下所示

{#each $members as member (get(member).id)}
    <CrewMemberListItem
        {member}
        {pushToBuffer}
        deleteFunction={deleteMember}
    />
{/each}

相对于此

{#each $members as member}
    <CrewMemberListItem
        {member}
        {pushToBuffer}
        deleteFunction={deleteMember}
    />
{/each}

看来 (get(member).id) 正在帮助 svelte 意识到这些差异很大,不能仅通过查看列表长度来正确更改 UI。

我的测试表明这可以按要求工作。给未来的自己 RTFM 的提示 :)

再次感谢@pilchard