In this mini-tutorial we are going to see two different ways of communication between components in Svelte 3: a callback passed as prop and event dispatcher.
A callback method is the way you do communication between components in React. A parent component passes a callback method to a child, and then, child invokes it.
This one is a typical way you do communication in Vue.js (although, it also allows you to use callbacks as props). In this type of communication, a component triggers some events on it's self, and then someone (a parent component) will listen to it and do something once triggered.
Svelte allows you to use both of them (as Vue does).
Here we have a simple Guess a Number project. It consist of 3 components: App (parent component), SecretValue (events based communication) and GuessComponent (prop passing). Under the project, there is a detailed explanation of both methods with small snippets, but I think it's better to see a complete project in order to understand better how it works.
<script>
import { onMount } from "svelte";
import SecretValue from "./SecretValue.svelte";
import GuessComponents from "./GuessComponent.svelte";
let secret = null;
let showSecret = false;
const getRandomInt = (min, max) => {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
const guessNumber = () => {
showSecret = false;
secret = getRandomInt(1, 10);
console.log(secret);
}
const onGuess = value => {
if(value == secret){
showSecret = true;
}
}
onMount(() => {
guessNumber();
});
</script>
<main>
<h1>Guess a Number</h1>
<SecretValue showSecret={showSecret} secret={secret} on:restart={guessNumber} />
<GuessComponents onGuess={onGuess} />
</main>
<style>
main {
text-align: center;
padding: 1em;
max-width: 240px;
margin: 0 auto;
}
h1 {
color: #ff3e00;
text-transform: uppercase;
font-size: 4em;
font-weight: 100;
}
@media (min-width: 640px) {
main {
max-width: none;
}
}
</style>
<script>
import { createEventDispatcher } from 'svelte';
export let secret = null;
export let showSecret = false;
const dispatch = createEventDispatcher();
const playAgain = () => {
dispatch("restart");
}
</script>
<div>
<p>{showSecret ? secret : "???"}</p>
{ #if showSecret }
<p>You won</p>
<button on:click={playAgain}>Play again</button>
{ /if }
</div>
<script>
let guessValue = "";
export let onGuess = null;
const guess = e => {
onGuess(guessValue);
}
</script>
<div>
<input bind:value={guessValue} />
<button on:click={guess}>Guess</button>
</div>
Let's take a look at SecretValue.svelte. In order to trigger events we must create a dispatcher:
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
Now, you can use dispatch object to trigger events on the component:
dispatch("event_name");
To listen to this event in parent component just add
on:event_name
on child and pass a method as a parameter (see App.svelte). The data you want to trigger will be passed as a detail property of the event.<!-- Parent.svelte -->
<script>
import Child from "./Child.svelte";
const sayHello = (e) => {
alert("Hello " + e.detail);
}
</script>
<Child on:hello={sayHello} />
<!-- Child.svelte -->
<script>
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
const triggerEvent = () => {
dispatch("hello", "Rock");
}
</script>
<button on:click={triggerEvent}>Call callback</button>
The callback method is very simple: create a function on parent component and pass it to child:
<!-- Parent.svelte -->
<script>
import Child from "./Child.svelte";
const callback = (message) => {
}
</script>
<Child callback={callback} />
<!-- Child.svelte -->
<script>
export let callback;
const callCallback = () => {
callback("test message");
}
</script>
<button on:click={callback}>Call callback</button>
Personally, I prefer an event-based communication, but I don't think it's actually better. The only problem with props is that it can cause problems if badly managed, but normally, both of them are ok. In real life, I would opt for storage.
You may also be interested in: