Магазин Svelte не запускает обмен при обновлении вложенных компонентов

Допустим, я хочу создать многоцветный инструмент выбора с svelte, возможно, чтобы позволить пользователю выбрать цвет переднего плана и цвет фона. Моя модель данных, которая выглядит так:

{
  foreground: {
    r: 100,g:100,b:100
  },
  background: {
    r: 200,g:200,b:200
  }
};

Так что мой app.js

    import AppUI from './App.html';
import { Store } from 'svelte/store.js';

const defaultData = {
  foreground: {
    r: 100,g:100,b:100
  },
  background: {
    r: 200,g:200,b:200
  }
};

const store = new Store(defaultData);

window.store = store; // useful for debugging!

store.onchange(() => console.log('something changed'));

var app = new AppUI({
  target: document.querySelector( '#main' ),
  store
});

export default app;

Тогда я могу построить RGBSelector компонент для повторного использования:

  <input type="range" min=0 max=255 step=1 bind:value=data.r/>{{data.r}}
  <input type="range" min=0 max=255 step=1 bind:value=data.g/>{{data.g}}
  <input type="range" min=0 max=255 step=1 bind:value=data.b/>{{data.b}}

И мой App.html довольно просто:

foreground:
<RGBSelector bind:data=$foreground/>

background:
<RGBSelector bind:data=$background/>

<script>
  import RGBSelector from './RGBSelector.html';

  export default {
    components: {
      RGBSelector
    }
  };
</script>

Похоже, это работает, в основном. Работает двусторонняя привязка на входах диапазона (обновляются метки), а хранилище даже обновляется (проверяется проверкой store._state в консоли). Так что я верю bind ключевые слова в RGBSelector передают изменения там, где они объявлены в Appчто в свою очередь bindПринося их в магазин.

Беда в том, store.onchange Обработчик не стреляет. Кто-нибудь может увидеть, что я делаю не так?

Полный пример: https://glitch.com/edit/

1 ответ

Решение

Это ошибка в Svelte, а не в вашем приложении! Оказывается, привязки компонентов не очень хорошо store - bind:data=$foreground просто обновляется $foreground в вашем <App> компонент, а не обновление foreground в вашем магазине.

Отслеживание проблемы здесь: https://github.com/sveltejs/svelte/issues/1100

К сожалению, нет хорошего обходного пути - пока мы не исправим это, вам нужно будет сделать что-то вроде этого:

foreground: <RGBSelector bind:data=foreground/>
background: <RGBSelector bind:data=background/>
text: <Textinput bind:value=text/>

<script>
  import RGBSelector from './RGBSelector.html';
  import Textinput from './Textinput.html';

  export default {
    components: {
      RGBSelector, Textinput
    },

    oncreate() {
      this.observe('foreground', foreground => {
        this.store.set({ foreground });
      });

      this.observe('background', background => {
        this.store.set({ background });
      });

      this.observe('text', text => {
        this.store.set({ text });
      });
    }
  };
</script>

И в вашем файле JS это:

var app = new App({
  target: document.body,
  data: defaultData,
  store
});

Если изменения могут идти обоими путями, вам также необходимо следить за свойствами магазина, стараясь предотвратить бесконечные циклы обновления:

// inside `oncreate` — would also need to do this
// for `background` and `text`
let foregroundUpdating = false;

this.observe('foreground', foreground => {
  if (foregroundUpdating) return;
  foregroundUpdating = true;
  this.store.set({ foreground });
  foregroundUpdating = false;
});

this.store.observe('foreground', foreground => {
  if (foregroundUpdating) return;
  foregroundUpdating = true;
  this.set({ foreground });
  foregroundUpdating = false;
});

Воссоздание функциональности таких привязок, очевидно, немного обременительно, поэтому мы постараемся исправить эту ошибку в ближайшее время.

Другие вопросы по тегам