Этот `dispatch()` полностью игнорируется. Почему?

Я создал воспроизведение проблемы, из-за которой диспетчеризация Svelte не вызывается:

Действия по воспроизведению

  1. Откройте репродукцию

  2. Откройте консоль браузера

  3. Перейдите на страницу «О нас» по ссылке.

  4. Я мог бы увидеть сообщение: «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) полностью игнорируется.

Почему?

Чтобы внести ясность, термин «REPL» относится к таким вещам, как приглашение в консоли браузера, где вы можете вводить операторы и оценивать их. Это означает «Цикл чтения-оценки-печати». Связанный сайт stackblitz не является REPL.

Pointy 28.04.2024 10:47

если вы заключаете dispatch('input', value); в setTimeout, похоже, это работает - возможно, вы используете отправку слишком рано (я не знаком с жизненными циклами компонентов svelte, чтобы сообщить вам, как это сделать правильно)

Jaromanda X 28.04.2024 10:56

@JaromandaX спасибо. Я не могу использовать здесь setTimeout, потому что он создает бесконечный цикл!

Fred Hors 28.04.2024 11:00

эм, нет, это не так, потому что именно так я определил, что с учетом тайм-аута все работает так, как ожидалось, без бесконечного цикла - я имею в виду, как может быть бесконечный цикл только потому, что вы отправляете событие «позже»? изменить: вы, вероятно, обернули больше, чем я предложил в setTimeout .... ТОЛЬКО dispatch ... ничего больше - обратите внимание, я НЕ предлагаю это решение - как я уже сказал, я не знаком с компонентом svelte жизненные циклы, чтобы предложить правильное решение для ваших требований

Jaromanda X 28.04.2024 11:02

возможно, вы захотите отправить внутрь onMount

Jaromanda X 28.04.2024 11:11

на самом деле, если вы переместите этот код в onMount, вам, вероятно, не понадобится отправлять «вручную»!

Jaromanda X 28.04.2024 11:15

Ага. В этом простом случае это работает, но в моем реальном приложении — нет, потому что результат поступает из другого реактивного хранилища.

Fred Hors 28.04.2024 11:23

Я не могу помочь со svelte в целом, и никто не может помочь с кодом, который вы не показали. Я поражен, что, не зная svelte, помог с кодом, который вы показали.

Jaromanda X 28.04.2024 11:24

очень сложно воспроизвести полный код!

Fred Hors 28.04.2024 11:25

действительно - но теперь вы знаете о onMounted - вы кое-чему научились

Jaromanda X 28.04.2024 11:25

Думаю, причина в этом: github.com/sveltejs/svelte/issues/4470

Fred Hors 28.04.2024 11:45
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
11
69
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Этапы размножения:

  1. Перейдите на страницу «О программе»
  2. ✅ Обратите внимание, что handleInput не регистрируется в консоли браузера (это не удалось)

Ваши реактивные операторы срабатывают до того, как прослушиватель событий 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} />

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