svelte: Event is not dispatched after component is loaded
Describe the bug Event from component is not dispatched (from reactive function) after component is loaded.
To Reproduce
https://svelte.dev/repl/2b0b7837e3ba44b5aba8d7e774094bb4?version=3.19.1
Expected behavior
Event is dispatched after component is loaded.
Information about your Svelte project:
- Your browser and the version: Google Chrome | 80.0.3987.87 (Official Build) (64-bit)
- Your operating system: Ubuntu 18.04.4 LTS
- Svelte version: 3.19.1
Severity
Low, I think.
Additional context
When I call dispatch in the setTimeout()
with zero delay then it’s working corectlly.
If this is desired behaviour then I think it’s appropriate to write notice to documentation:
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Reactions: 2
- Comments: 15 (1 by maintainers)
Would it be possible to display console warning if dispatch was called before onMount or before parent attached listener to event?
Nope. For me it works even without runes mode. Only svelte 5.
@Conduitry wrote:
I suspect that is correct. (Confirmed. See logs below.)
Should we update the title (since “event is not dispatched” is not quite accurate)?: Events dispatched from child component get lost because dispatched before event listeners attached in parent component
I would love to see a diagram in the docs that illustrates this sequence of events in detail (issue forthcoming!)…
I’m still not quite convinced. Wouldn’t Svelte be better if users didn’t have to worry about events getting lost (due to a lifecycle event / component tree initialization step order that they have absolutely no control over), and didn’t have to resort to kludges like
await tick()
(from #5405) in order to dispatch an event from a child (often, an initial value) in a way that the parent actually receives the event?Or at least provide an elegant/easy option to synchronize/postpone the timing of these things for cases where that is preferred. Maybe something like:
, which would instruct Svelte to queue up any
fill
events dispatched by<Child>
until self (parent) has finished mounting (and therefore finished attaching all listeners)?Or something like:
or
to queue and defer all events dispatched by
<Child>
. Pretty ugly, but just brainstorming…Seems like that should just be the default behavior…
Note: I believe there may be related confusing race condition (not technically a race condition since it’s deterministic, but what do you call it?) issues related to the use of
use:
andbind:
in a parent component (issues for these may be forthcoming…)…@MrSrsen wrote:
Technically, that’s incorrect (see @Conduitry’s explanation for the actual reason for the behavior): reactive statements are run before
onMount
is fired, as this console output (from my fork of your REPL) shows:This also seems to confirm @Conduitry’s hypothesis that listener isn’t attached in parent until after
$: isFilled
is called in the child.So it sounds like you would be someone who would actually prefer that the current behavior not change?
I’d be curious to see a concrete example where the current behavior would actually be useful/desirable (and if so, whether the perceived problem might actually be a non-issue in those cases, or easily worked around).
Your original REPL is actually a counterexample/the opposite of what you described here — a case where everything has been sufficiently initialized (the correct values for
value
andlength
(“Some text” and 5, respectively) have already been assigned via props by this point) and where it would be more useful to have it always dispatch thefill
event, even from the initial invocation of the child’s$:
statement.You mean (in your initial example) calling
isFilled
from both$: isFilled(value)
and from anonMount
callback?Sure, that works, but seems unfortunate that one needs to have that duplication.
Another option (which I like even better) is to use the
tick()
workaround from #5405: see my updated REPL. Then you don’t have to add anonMount
callback.@plibither8
I’m still curious if there’s a better workaround, but my personal favorite so far is the
await tick()
trick from #5405…Oops, looks like you linked to the same REPL as the OP. Did you start from their REPL, make some changes, but forget to save your changes (which would have created a new REPL URL)? Would be interested to see what you were trying to show, about what you would like it to do.