Это проблема с массивом push() в Svelte или я что — то делаю не так?

#arrays #promise #push #svelte

Вопрос:

Я ломал голову над этой проблемой уже несколько часов, и хотя я нашел обходной путь для решения проблемы, я не могу смириться с тем фактом, что это вообще происходит. Я этого не понимаю. Похоже, существует какая-то проблема в использовании Array.push() в обработчике обещаний. Я создал приведенный ниже тестовый код, чтобы продемонстрировать его, и он воспроизводим в Svelte REPL. Я просто делаю что-то не так?

 <script>
  const myPromise = new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('foo');
    }, 300);
  });

  let itemsA = [];
  let itemsB = [];

  const addItem = (item) => {
    itemsA[itemsA.length] = item;
    itemsB.push(item);
  }
    
  const loadItems = (last) => {
    addItem("Begin");

    myPromise
      .then((value) => {
        addItem(value);
      });

    addItem("End");
    return true;
  };

  loadItems();
</script>

<div>Items A: {itemsA}</div>
<div>Items B: {itemsB}</div>
 

Я бы подумал, что itemsB.push(item) должен делать то же самое, что и itemsA[itemsA.length] = item, и это так, за исключением случаев, когда он вызывается из обработчика обещаний.

Вместо этого я получаю следующие результаты:

 Items A: Begin,End,foo
Items B: Begin,End
 

Правка: Я исключил обещания как источник странностей. Следующий код иллюстрирует это более просто.

 <script>
  let itemsA = [];
  let itemsB = [];

  const addItem = (item) => {
    itemsA[itemsA.length] = item;
    itemsB.push(item);
  }

    const clickHandler = () => {
        addItem('click');
    }
    
    addItem('load');
</script>

<div>Items A: {itemsA}</div>
<div>Items B: {itemsB}</div>
<button on:click={clickHandler}>Click Me</button>
 

Комментарии:

1. Вот как работают обещания. addItem Во внешней области выполнения loadItems выполняется перед addItem внутренним обработчиком обещания. Для получения дополнительной информации здесь есть отличное видео: youtube.com/watch?v=8aGhZQkoFbQamp;ab_channel=JSConf

Ответ №1:

На самом деле это не имеет никакого отношения к обещанию. Когда вы добавляете кнопку и регистрируете массивы, вы видите, что » foo «также находится в «itemsB», он просто не отображается. Из стройных документов

Поскольку реактивность Svelte основана на назначениях, использование методов массива, таких как .push() и .splice (), не будет автоматически запускать обновления. Для запуска обновления требуется последующее назначение.
Соответствующий учебник

Вы можете использовать .push (), если за ним следует переназначение массива самому себе

 itemsB.push(item);
itemsB = itemsB
 

или в качестве альтернативы используйте синтаксис оператора распространения

 itemsB = [...itemsB, item]
 

Вот повторный вариант, чтобы попробовать это

Комментарии:

1. Это полезно, и я буду уверен, что не буду использовать push (я сам немного сузил его, как вы можете видеть из редактирования, которое я добавил, как раз когда вы добавляли этот ответ).. Хотя я не уверен, что понимаю, почему Стройность не делает этого. Разве не так?

2. Я не уверен, что понимаю, что ты имеешь в виду..? Вы имеете в виду, почему он не отображается просто с помощью .push()?

3. Да, именно это я и имею в виду.

4. Что ж, я думаю, мне придется передать этот вопрос создателям Svelte… 🙂 Я просто принял (на данный момент), что задание важно для того, чтобы все вело себя так, как ожидалось