Может ли компонент 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, а только одну ссылку на один компонент.

🤔 А знаете ли вы, что...
JavaScript является одним из трех основных языков веб-разработки, вместе с HTML и CSS.


1
55
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}

Насколько я знаю, дочерний компонент не может получить доступ к ссылке на себя, но его нужно будет создать через 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 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.