svelte icon indicating copy to clipboard operation
svelte copied to clipboard

onMount within action will not fire for initially hidden component

Open FireMakeThunder opened this issue 3 years ago • 3 comments

Describe the bug

If onMount is invoked from within a use:action function, and is declared on a child node within an initially unmounted component, the code within onMount will not run when said component is mounted.

However, if the component is set to mount when App.svelte is mounted, the code within use:action's onMount will run, though the returned function intended to be called through onDestroy will not run when the component is destroyed.

This issue originates from this discord thread

Reproduction

https://svelte.dev/repl/7aa63b40621344c1a7459516c2ca03a4?version=3.49.0

Logs

No response

System Info

N/A

Severity

annoyance

FireMakeThunder avatar Jul 28 '22 07:07 FireMakeThunder

Since Action receives an HTMLElement, so it cannot follow below rule.

https://svelte.dev/docs#run-time-svelte-onmount

It must be called during the component's initialisation

I have implemented an alternative. Would this be a workaround?

https://svelte.dev/repl/aa220a4dc8ef4ab9ad79faa7feb7200d?version=3.49.0

baseballyama avatar Aug 06 '22 13:08 baseballyama

@baseballyama I'm the original poster of the discord discussion. Thanks for your input. It is certainly a workaround. But for a self-contained action (say an action that does some internal stuff when component has been mounted), requiring users to manually execute the exported onMountProcess is probably not the best experience.

And now that i have thought about it, you are right. action is executed when HTMLElement is created, not during component initialization. In fact, if we look at the compiled code in the original repl, the action is called during the mount instruction:

// portion of compiled JS of `C1.svelte`
m(target, anchor) {
	insert(target, main, anchor);

	if (!mounted) {
		dispose = action_destroyer(action_action = action.call(null, main));
		mounted = true;
	}
},

So the bottom line is we should not use onMount in action, although the fact that it sometimes works still bothers me (try removing the if condition in the original repl).

For people coming to this thread, here is my workaround (thanks Geoff Rich)

import { tick } from 'svelte';
export function yourAction() {
  // ...
  
  tick().then(() => {
    // do stuff for when mounted
  });
  
  // ...
}

FWIW, I have also tried setTimeout(..., 0) in place of tick and it works as well, although i think we should stick to tick here. Also, I imagine that beforeUpdate and afterUpdate can be used in action and might come in handy in some use cases.

@tanhauhau (sorry for tagging) consider you've made this wonderful video about component initialization, perhaps you can give some insights and decide whether this is a proper issue (or close it)?

vnphanquang avatar Aug 06 '22 14:08 vnphanquang

How about something like that? https://svelte.dev/repl/237823ed53614c60902db0745dff0d6e?version=3.49.0

PatrickG avatar Aug 06 '22 16:08 PatrickG