|
2 | 2 | title: use: |
3 | 3 | --- |
4 | 4 |
|
5 | | -- template syntax |
6 | | -- how to write |
7 | | -- typings |
8 | | -- adjust so that `$effect` is used instead of update/destroy? |
9 | | - |
10 | | -```svelte |
11 | | -<!--- copy: false ---> |
12 | | -use:action |
13 | | -``` |
14 | | - |
15 | | -```svelte |
16 | | -<!--- copy: false ---> |
17 | | -use:action={parameters} |
18 | | -``` |
19 | | - |
20 | | -```ts |
21 | | -/// copy: false |
22 | | -// @noErrors |
23 | | -action = (node: HTMLElement, parameters: any) => { |
24 | | - update?: (parameters: any) => void, |
25 | | - destroy?: () => void |
26 | | -} |
27 | | -``` |
28 | | - |
29 | | -Actions are functions that are called when an element is created. They can return an object with a `destroy` method that is called after the element is unmounted: |
| 5 | +Actions are functions that are called when an element is mounted. They are added with the `use:` directive, and will typically use an `$effect` so that they can reset any state when the element is unmounted: |
30 | 6 |
|
31 | 7 | ```svelte |
32 | 8 | <!--- file: App.svelte ---> |
33 | 9 | <script> |
34 | | - /** @type {import('svelte/action').Action} */ |
35 | | - function foo(node) { |
| 10 | + /** @type {import('svelte/action').Action} */ |
| 11 | + function myaction(node) { |
36 | 12 | // the node has been mounted in the DOM |
37 | 13 |
|
38 | | - return { |
39 | | - destroy() { |
40 | | - // the node has been removed from the DOM |
41 | | - } |
42 | | - }; |
| 14 | + $effect(() => { |
| 15 | + // setup goes here |
| 16 | +
|
| 17 | + return () => { |
| 18 | + // teardown goes here |
| 19 | + }; |
| 20 | + }); |
43 | 21 | } |
44 | 22 | </script> |
45 | 23 |
|
46 | | -<div use:foo /> |
| 24 | +<div use:myaction>...</div> |
47 | 25 | ``` |
48 | 26 |
|
49 | | -An action can have a parameter. If the returned value has an `update` method, it will be called immediately after Svelte has applied updates to the markup whenever that parameter changes. |
50 | | - |
51 | | -> [!NOTE] Don't worry that we're redeclaring the `foo` function for every component instance — Svelte will hoist any functions that don't depend on local state out of the component definition. |
| 27 | +An action can be called with an argument: |
52 | 28 |
|
53 | 29 | ```svelte |
54 | 30 | <!--- file: App.svelte ---> |
55 | 31 | <script> |
56 | | - /** @type {string} */ |
57 | | - export let bar; |
58 | | -
|
59 | | - /** @type {import('svelte/action').Action<HTMLElement, string>} */ |
60 | | - function foo(node, bar) { |
61 | | - // the node has been mounted in the DOM |
62 | | -
|
63 | | - return { |
64 | | - update(bar) { |
65 | | - // the value of `bar` has changed |
66 | | - }, |
67 | | -
|
68 | | - destroy() { |
69 | | - // the node has been removed from the DOM |
70 | | - } |
71 | | - }; |
| 32 | + /** @type {import('svelte/action').Action} */ |
| 33 | + function myaction(node, +++data+++) { |
| 34 | + // ... |
72 | 35 | } |
73 | 36 | </script> |
74 | 37 |
|
75 | | -<div use:foo={bar} /> |
| 38 | +<div use:myaction={+++data+++}>...</div> |
76 | 39 | ``` |
77 | 40 |
|
78 | | -## Attributes |
| 41 | +The action is only called once (but not during server-side rendering) — it will _not_ run again if the argument changes. |
| 42 | + |
| 43 | +> [!LEGACY] |
| 44 | +> Prior to the `$effect` rune, actions could return an object with `update` and `destroy` methods, where `update` would be called with the latest value of the argument if it changed. Using effects is preferred. |
79 | 45 |
|
80 | | -Sometimes actions emit custom events and apply custom attributes to the element they are applied to. To support this, actions typed with `Action` or `ActionReturn` type can have a last parameter, `Attributes`: |
| 46 | +## Typing |
| 47 | + |
| 48 | +The `Action` interface receives three optional type arguments — a node type (which can be `Element`, if the action applies to everything), a parameter, and any custom event handlers created by the action.: |
81 | 49 |
|
82 | 50 | ```svelte |
83 | 51 | <!--- file: App.svelte ---> |
84 | 52 | <script> |
| 53 | + import { on } from 'svelte/events'; |
| 54 | +
|
85 | 55 | /** |
86 | | - * @type {import('svelte/action').Action<HTMLDivElement, { prop: any }, { 'on:emit': (e: CustomEvent<string>) => void }>} |
| 56 | + * @type {import('svelte/action').Action< |
| 57 | + * HTMLDivElement, |
| 58 | + * null, |
| 59 | + * { |
| 60 | + * onswiperight: (e: CustomEvent) => void; |
| 61 | + * onswipeleft: (e: CustomEvent) => void; |
| 62 | + * // ... |
| 63 | + * }>} |
87 | 64 | */ |
88 | | - function foo(node, { prop }) { |
89 | | - // the node has been mounted in the DOM |
90 | | -
|
91 | | - //...LOGIC |
92 | | - node.dispatchEvent(new CustomEvent('emit', { detail: 'hello' })); |
93 | | -
|
94 | | - return { |
95 | | - destroy() { |
96 | | - // the node has been removed from the DOM |
97 | | - } |
98 | | - }; |
| 65 | + function gestures(node) { |
| 66 | + $effect(() => { |
| 67 | + // ... |
| 68 | + node.dispatchEvent(new CustomEvent('swipeleft')); |
| 69 | +
|
| 70 | + // ... |
| 71 | + node.dispatchEvent(new CustomEvent('swiperight')); |
| 72 | + }); |
99 | 73 | } |
100 | 74 | </script> |
101 | 75 |
|
102 | | -<div use:foo={{ prop: 'someValue' }} onemit={handleEmit} /> |
| 76 | +<div |
| 77 | + use:gestures |
| 78 | + onswipeleft={next} |
| 79 | + onswiperight={prev} |
| 80 | +>...</div> |
103 | 81 | ``` |
0 commit comments