Магазин 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;
});
Воссоздание функциональности таких привязок, очевидно, немного обременительно, поэтому мы постараемся исправить эту ошибку в ближайшее время.