Может ли компонент Svelte скопировать собственный экземпляр?

Для вложенных компонентов Svlete, где Outer содержит несколько Inner, можно ли создать диспетчер с createEventDispatcher в Inner, который будет связываться с экземпляром, вызвавшим диспетчер?

Outer.svelte будет выглядеть примерно так

<script lang = "ts">
  import Inner from "./Inner.svelte";

  /* placeholder array of 0-10 elements, to make it clear the number of Inners
   * in this component is different depedning on some outside factors */
  let dynamicContent = Array.from({length: Math.random() * 10}, () => "something");

  // How is it possible to set this?
  let lastSelectedInner: Inner | null = null;
</script>

{#each dynamicContent as item}
  <Inner on:select = {(event) => lastSelectedInner = event.detail} />
{/each}

И Inner.svelte будет выглядеть примерно так:

<script lang = "ts>
  import { createEventDispatcher } from "svelte";
  const dispatch = createEventDispatcher();
</script>

<button on:click = {() => dispatch("select", /* how do I forward the instance here? */)} >
  <p>Click me</p>
</button>

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

Почему родительскому компоненту нужна ссылка на экземпляр дочернего компонента? Зачастую достаточно передать данные в экземпляр дочернего компонента с помощью реквизитов, и если родительскому элементу нужно каким-то образом изменить дочерний компонент, можно просто изменить реквизиты за один проход.

Peppe L-G 10.06.2024 10:32

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

goose_lake 10.06.2024 10:35
Поведение ключевого слова "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) для оценки ваших знаний,...
1
2
55
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Судя по вашему комментарию, похоже, что экземпляру родительского компонента на самом деле не нужен доступ к экземпляру дочернего компонента, а только (некоторые) к данным в экземпляре дочернего компонента. Таким образом, экземпляр дочернего компонента может передавать эти данные в событии, а не сам экземпляр компонента. А может быть передача данных вообще не нужна?

Внешний.стройный

<script lang = "ts">
  import Inner from "./Inner.svelte";
  
  
  let items = [{
    id: 1,
    name: `a`,
  }, {
    id: 2,
    name: `b`,
  }]

  let selectedItem: Object | null = null; // I don't know TS, so unsure about type ^^'

</script>

{#each items as item}
  <Inner on:select = {(event) => selectedItem = item} />
{/each}

{#if selectedItem}
  <h1>Selected</h1>
  <div>Id: {selectedItem.id}</div>
  <div>Name: {selectedItem.name}</div>
{/if}

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

goose_lake 10.06.2024 10:49

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

goose_lake 10.06.2024 10:54

Насколько мне известно (но я не уверен), экземпляр компонента не может получить ссылку на себя (если только вы не обойдете это, используя родительский компонент нежелательным для вас способом). Итак, краткий ответ на ваш вопрос, вероятно, невозможен. Тогда предложение обходных путей - хороший ответ, ИМО. И, возможно, вы не ищете конкретное обходное решение, которое я предложил, но другие люди в будущем, которые думают, что у них такая же проблема, как и вы, и найдут этот вопрос, могут найти это обходное решение хорошим решением для себя. Но если вы не согласны, не стесняйтесь поставить минус, для этого и нужна кнопка.

Peppe L-G 10.06.2024 11:06

Я бы не хотел ставить минус, поскольку вы прикладываете усилия, чтобы предложить ответ, и это просто кажется грубым, но, возможно, было бы хорошо начать ответ с чего-то вроде: короткий ответ «это невозможно из-за того, что Svelte не позволяет ..., но возможным обходным решением является ...", а не "вам, вероятно, это не нужно", поскольку сама необходимость зависит от вопроса, а предлагаемое решение представляет собой обходной путь с несколькими недостатками.

goose_lake 10.06.2024 11:12

Насколько я знаю, дочерний компонент не может получить доступ к ссылке на себя, но его нужно будет создать через bind:this в родительском компоненте и передать как реквизит.

Это был бы способ установить lastSelectedInner без добавления дополнительной логики в компонент Inner.

<script>
  import Inner from "./Inner.svelte";

  /* placeholder array of 0-10 elements, to make it clear the number of Inners
   * in this component is different depedning on some outside factors */
  let dynamicContent = Array.from({length: Math.random() * 10}, () => "something");

    let innerRefs = []
    
  // How is it possible to set this?
  let lastSelectedInner = null;
    $: console.info(lastSelectedInner)   
</script>

{#each dynamicContent as item, index}
  <Inner bind:this = {innerRefs[index]}
        on:select = {() => lastSelectedInner = innerRefs[index]} />
{/each}

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

goose_lake 10.06.2024 11:01
Ответ принят как подходящий

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

Я наткнулся на Svelte REPL (не знаю, кто автор), который показывает, как сделать это возможным с помощью специального элемента <svelte:self>. Вот изложенное там решение, адаптированное к этому вопросу. Inner.svelte:

<script lang = "ts">
  export let outer = true;
  export let component = null;

  import { createEventDispatcher } from "svelte";
  const dispatch = createEventDispatcher();
</script>

{#if outer}
  <svelte:self 
    bind:this = {component}
    outer = {false}
    on:select = {() => dispatch("select", component)}
  />
{/if}

{#if !outer}
  <button on:click = {() => dispatch("select")} >
    <p>Click me</p>
  </button>
{/if}

Этот подход не самый читаемый, поскольку он требует вложения внутреннего компонента внутрь себя и условного отображения содержимого только во вложенном компоненте. Тем не менее, он достигает именно того результата, который позволяет отправлять событие из компонента, который в деталях передает одну правильно типизированную ссылку.

Обновлено: обновлено в соответствии с комментарием @Corrl.

Есть ли у вас работающий Repl, использующий этот подход?

Corrl 10.06.2024 12:45

Я думаю, что его нужно настроить, чтобы он работал svelte.dev/repl/908de9703eb4472f8e744d3ca0a7f331?version=4.2‌​.18

Corrl 10.06.2024 12:58

@Corrl Хорошая мысль, спасибо, что указали на это. Я написал это очень быстро и еще не проверял. Действительно, необходимо перенаправить событие внутреннего-внутреннего компонента во внешний-внутренний компонент (извините за путаницу в именах, переменные в REPL были названы так же, как и компоненты в моем вопросе).

goose_lake 10.06.2024 13:04

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