I have a component called WastedTime.svelte
with a value wastedTime
. There's also a function to change the value to 50
(in my real code, this does an animation but this is a reduced test case for Stack Overflow).
To allow the child function to be called from a parent, I have used <script context="module">
per the Svelte docs:
<script context="module">
var wastedTime = 0;
export function changeNumber(){
console.log('changing number')
wastedTime = 50
}
</script>
<script>
// Putting 'var wastedTime = 0' here doesn't work either
</script>
<h1>Wasted time: {wastedTime}</h1>
The parent calls the function in the child from onMount
:
<script>
import { onMount } from 'svelte';
import WastedTime, {changeNumber } from './WastedTime.svelte';
onMount(() => {
changeNumber()
});
</script>
<WastedTime />
The problem is that since wastedTime
is referred to in <script context="module">
, it can't seem to change wastedTime
. The exported function runs, but wastedTime
stays at 0.
I have tried: - Putting var wastedTime = 0
in <script context="module">
- Putting var wastedTime = 0
in <script>
Neither works.
How can I export a function from a Svelte component that changes a value in the component?
<script context="module">
isn't reactive — changes to variables inside this block won't affect individual instances (unless you were changing a store value, and every instance was subscribed to that store).
Instead, export the changeNumber
function directly from the instance, and get a reference to it with bind:this
:
<script>
var someNumber = 0;
export function changeNumber(){
console.log('changing number')
someNumber = 56
}
</script>
<h1>Wasted time: {someNumber}</h1>
<script>
import { onMount } from 'svelte';
import WastedTime from './WastedTime.svelte';
let wastedTimeComponent;
onMount(() => {
wastedTimeComponent.changeNumber()
});
</script>
<WastedTime bind:this={wastedTimeComponent} />
Demo here: https://svelte.dev/repl/f5304fef5c6e43edb8bf0d25d634f965
Simplified version of Rich's answer:
<script>
import Time from './Time.svelte';
let timeComponent;
let time;
</script>
<Time bind:this={timeComponent} bind:time />
<h1>Spent time: {time} ms</h1>
{#if timeComponent}
<button on:click={() => timeComponent.spendTime() }>Click me</button>
{:else}
Loading...
{/if}
<script>
export var time = 0;
export function spendTime() {
time += 50;
}
</script>
The key here is export function
.
Well, that's a damn good question!
My First Attempt:
I've tried @Rich Harris answer (export a function from within the component, bind it when using the component with onMount
event listener). The concept is indeed solid, but my problem was a little bit more complex - I've tried to pass an event with parameter to be invoked from the outside. And yes - this parameter is forged using {#await}
.. so... no luck with that approach
My Second Attempt:
After learning more about how svelte handles events (I'm a newbie to svelte and learning as I progress), I've found this great article. In short: let's make our component truly-event oriented! In your question - you actually trying to implement onload
event... so.. why shouldn't we do just that?
component.svelte
<script>
import { createEventDispatcher, onMount } from 'svelte';
const dispatch = createEventDispatcher();
function doSomething() { console.log('wowza!') }
// wait for onMount to trigger, then dispatch event named "load"
onMount(() => dispatch('load',
{
data: 'yay',
doSomething
}));
</script>
app.svelte
<script>
import { Component } from './component.svelte';
function component_load(event)
{
console.log(event.detail.data);
event.detail.doSomething();
}
</script>
<Component on:load={component_load} />
So - yep, I've learned something today: Also:
dispatch
can be triggered in response to other events - letting you constuct a complete life-cycle for your component AMAZING!
Parent component:
<script>
import Counter from './Counter.svelte'
let counterElement
</script>
<Counter bind:this={counterElement} />
<button on:click={_=> counterElement.add()}>Add</button>
Child component:
<script>
export const add =_=> count += 1
let count = 0
</script>
<div>Count: {count}</div>
Check it out:
https://svelte.dev/repl/70cff59aee444dd3ab772a244bd8fa36?version=3.48.0
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.