Как сохранить состояние компонентов Svelte в виртуальном списке?

Я разрабатываю компонент диаграммы Ганта в Svelte, и он состоит из сотен компонентов строк, каждый из которых содержит несколько компонентов задачи. Задачи можно перетаскивать и перемещать. Производительность является приоритетом, и я использую виртуальный список для отображения только видимых строк.

<div class="scrollable">
    {#each visibleRows as row (row.id)}
        <div class="row">
            {#each row.tasks as task (task.id)}
                <Task from={task.from} to={to}/>
            {/each}
        </div>
    {/each}
</div>

Проблема в том, что когда я перемещаю задачи и прокручиваю строки из представления, они уничтожаются, а когда я возвращаюсь к ним, их состояние сбрасывается. Этот REPL с использованием svelte-virtual-list иллюстрирует проблему https://svelte.technology/repl?version=2.13.5&gist=bdb4c523d2e1cf7e3aef452e3f24d988 Мне интересно, как лучше всего справиться с этой ситуацией.

В настоящее время я использую объект задачи в качестве опоры и обновляю его, ссылка остается прежней, и прокрутка не влияет на нее.

<Task {task}/>

Но внутри Задачи я обновляю состояние, подобное этому

const {task} = this.get();
task.from = new Date();
this.set({task});

и шаблон ссылается на каждую опору с помощью task.propname, и я не уверен, что это изящный способ сделать это, поскольку неясно, что именно устанавливается.

Я мог бы привязать переменные задачи вот так

<Task bind:from=task.from 
      bind:to={task.to}/>

Но нужно привязать много переменных (более 10), и я хочу, чтобы возможные будущие плагины обновляли новые реквизиты из компонента Task.

<Task {task} 
      {...task}/>

Это касается потенциально большего количества реквизитов, но я обновляю объект задачи в событии состояния следующим образом:

onstate({ changed, current, previous }) {
    const {task} = this.get();
    Object.assign(task, current);
    this.set({task});
},

Какой из них я должен предпочесть для повышения производительности или есть лучший способ справиться с этим?


person Ante Novokmet    schedule 05.10.2018    source источник
comment
Похоже, у вас нет выбора использовать onstate event. Какие у вас проблемы с использованием onstate event?   -  person Hassan Voyeau    schedule 05.10.2018
comment
Есть обновления по этому поводу?   -  person Hassan Voyeau    schedule 08.10.2018
comment
Я продолжу использовать первый подход, но переименую свойство task в _task, _data или _state, чтобы в дальнейшем отличать его как своего рода защищенное свойство состояния. Последний подход с onstate срабатывает при каждом изменении состояния, даже при тех, которые не должны в конечном итоге обновлять task, и легко получить в нем ненужные данные ...   -  person Ante Novokmet    schedule 09.10.2018


Ответы (1)


Вам следует изменить массив данных вместо изменения объекта. Изменяя объект внутри массива, Svelte не знает, что ваш массив изменился.

Мутация массива будет выглядеть примерно так в Svelte v3 и с использованием хранилища вместо простого массива:

// data.js
...
import { writable } from 'svelte/store';

export default writable(getData())
...

// App.svelte
<script>
...
import items from './data.js';

function updateContent(item) {
    const index = $items.indexOf(item)
    $items = [
        ...$items.slice(0, index),
        { ...item, content: 'updated content' },
        ...$items.slice(index + 1)
    ]
}
...
</script>

<VirtualList items={$items} let:item bind:start bind:end>
    ...
        <button on:click={() => updateContent(item)}>update content</button>
    ...
</VirtualList>

Полный пример: https://svelte.dev/repl?version=3.0.0-beta.28&gist=f8c7e96bb34906db2c3a5e85b4840017

Вы можете узнать больше об обновлении массивов и объектов здесь: https://svelte.dev/tutorial/updating-arrays-and-objects

person arve0    schedule 21.04.2019
comment
В вашем примере, где items создается в data.js, это не так, верно? И почему вы звоните $items в updateContent вместо items? - person user82395214; 13.12.2019