Я создал воспроизведение проблемы, из-за которой диспетчеризация Svelte не вызывается:
Откройте репродукцию
Откройте консоль браузера
Перейдите на страницу «О нас» по ссылке.
Я мог бы увидеть сообщение: «handleInput», но это не так.
<script>
import Select from 'svelte-select';
import { createEventDispatcher } from 'svelte';
export let value = undefined;
export let id = undefined;
const dispatch = createEventDispatcher();
let result;
let items = [
{ value: 'one', label: 'One' },
{ value: 'two', label: 'Two' },
{ value: 'three', label: 'Three' },
];
$: if (id !== undefined) {
result = id;
}
$: if (result != undefined) {
value = { value: 'custom', label: 'Custom' };
console.info("this should dispatch!")
dispatch('input', value);
console.info("is it dispatched?")
}
</script>
<Select {value} {items} on:change on:input />
dispatch('input', value)
полностью игнорируется.
Почему?
если вы заключаете dispatch('input', value);
в setTimeout
, похоже, это работает - возможно, вы используете отправку слишком рано (я не знаком с жизненными циклами компонентов svelte, чтобы сообщить вам, как это сделать правильно)
@JaromandaX спасибо. Я не могу использовать здесь setTimeout, потому что он создает бесконечный цикл!
эм, нет, это не так, потому что именно так я определил, что с учетом тайм-аута все работает так, как ожидалось, без бесконечного цикла - я имею в виду, как может быть бесконечный цикл только потому, что вы отправляете событие «позже»? изменить: вы, вероятно, обернули больше, чем я предложил в setTimeout .... ТОЛЬКО dispatch
... ничего больше - обратите внимание, я НЕ предлагаю это решение - как я уже сказал, я не знаком с компонентом svelte жизненные циклы, чтобы предложить правильное решение для ваших требований
возможно, вы захотите отправить внутрь onMount
на самом деле, если вы переместите этот код в onMount
, вам, вероятно, не понадобится отправлять «вручную»!
Ага. В этом простом случае это работает, но в моем реальном приложении — нет, потому что результат поступает из другого реактивного хранилища.
Я не могу помочь со svelte в целом, и никто не может помочь с кодом, который вы не показали. Я поражен, что, не зная svelte, помог с кодом, который вы показали.
очень сложно воспроизвести полный код!
действительно - но теперь вы знаете о onMounted
- вы кое-чему научились
Думаю, причина в этом: github.com/sveltejs/svelte/issues/4470
Этапы размножения:
Ваши реактивные операторы срабатывают до того, как прослушиватель событий on:input
прикрепится к компоненту <Select>
. Это может быть связано с тем, что реактивные операторы вызываются до монтирования DOM (или разметки компонента), а прослушиватели событий подключаются после монтирования компонента.
Причина, по которой ваш код setTimeout
работает, заключается в том, что он добавляет микрозадачу, которая, скорее всего, регистрируется после настройки прослушивателей событий; поэтому, когда сработает его функция обратного вызова, ваш слушатель on:input
получит отправленное событие. Аналогично, использование await tick()
заставляет ваш код работать по той же причине:
async function dispatchEvent () {
value = { value: 'custom', label: 'Custom' };
console.info("this should dispatch!")
// wait for all microtasks to complete before continuing
await tick()
dispatch('input', value);
console.info("is it dispatched?")
}
$: if (result != undefined) {
dispatchEvent()
}
С учетом вышесказанного, за множеством реактивных заявлений сложно следить. Я рекомендую провести рефакторинг для использования прослушивателей событий в вашем CustomSelect.svelte
, что можно комбинировать с пересылкой событий:
<Select on:input = {internalInputHandler} on:input on:change />
<!-- ^ handle input ^ forward input -->
Я также рекомендую отправлять события с собственным именем, а не переопределять собственные имена событий; таким образом вы сможете обрабатывать их отдельно и ожидать, что родной InputEvent
будет on:input
. Вы можете назвать отправленное событие input--id
:
<!-- Component.svelte -->
<script>
function handler() {
dispatch('input:component', { some: 'detail' })
}
</script>
<!-- +page.svelte -->
<Select on:input--id = {doSomething} on:input = {doSomethingElse} />
Чтобы внести ясность, термин «REPL» относится к таким вещам, как приглашение в консоли браузера, где вы можете вводить операторы и оценивать их. Это означает «Цикл чтения-оценки-печати». Связанный сайт stackblitz не является REPL.