简体   繁体   中英

Keep track of state in child-component component from withing parent component in Svelte (Data-flow/communication from child to parent in Svelte)

As I am quite new to the way of reactive thinking I am having a hard time to grasp some basics concepts. I also think to this question there are many ways to solve this which is quite overwhelming for a begginer. So here is my simple question:

I have a parent component and a child component. The only thing (for now) that the parent component is doing is importing the child component and rendering it. The child component itself goes (on click) through an array of text and displays it. When reached the end I want to unmount this component. However, as far as I know, this is usually done from the parent. Eg by wrapping it in a pseudo if-statement like this:

{#if childNotFinished}
    <Child/>
{/if}

But I simply do not know what the best way is to communicate to the parent that the child is "done"

My two components look like this and are in the repl here ( https://svelte.dev/repl/c787b13ebe524af8af3d97d71e7c8510?version=3.49.0 ):

# App.svelte
<script>
import Intro from "./Intro.svelte"
</script>

<Intro></Intro>
<!--
{#if IntroFinished}
Do something new, import a new component, ....
{/if}
-->
# Intro.svelte
<script>
  let currentStep = 0;
  
  let steps = [
    { text: "this" },
    { text: "is" },
    { text: "a" },
    { text: "test" },
  ];

  function showNext() {
    if (currentStep === steps.length - 1) {
      return;
    }
    currentStep++;
  }

  function showPrev() {
    if (currentStep === 0) {
      return;
    }
    currentStep--;
  }
</script>

<button on:click={showPrev}>Last</button>
<button on:click={showNext}>Next</button>

<div>
  {steps[currentStep].text}
</div>

{#if currentStep === steps.length - 1}
  <button>Start New Thing</button>
{/if}

Maybe there are some best practices or good ressources on how to approach something like this. Or more general on data-flow (up and down) in svelte. It feels like there are coming so many new possibilities each time that I do not know which to use and how to solve this.

In this case I would either use a bound property or an event.

With the property approach you declare a property on the child:

export let finished = false;
{#if currentStep === steps.length - 1}
  <button on:click={() => finished = true}>Start New Thing</button>
{/if}

Which then can be read via bind: in the parent:

<script>
    import Intro from "./Intro.svelte";
    let finished = false;
</script>

{#if finished == false}
    <Intro bind:finished ></Intro>
{:else}
  Something else
{/if}

Via events you create a dispatcher and dispatch an event from the child component:

import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
{#if currentStep === steps.length - 1}
  <button on:click={() => dispatch('finished')}>Start New Thing</button>
{/if}

Which then is handled in the parent:

<script>
    import Intro from "./Intro.svelte";
    let finished = false;
</script>

{#if finished == false}
    <Intro on:finished={() => finished = true} ></Intro>
{:else}
  Something else
{/if}

An event is probably a bit cleaner, because the component is not supposed to revert its state, so there is no real need for it to be a property.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM