The global current_component is reset back to undefined in the App init before the promise in handle_promise is resolved. Because of this the parent_component in the Child init is undefined, and subsequently the context is empty.
The parent_component in the Child init is correctly set to App if you change to something synchronous like e.g. {#await 'foo'}, so it might be that the approach of a global current_component has to be changed to fix this.
@EmilTholin This issue is biting me when trying to use the {#await ...} block to render a <Link> component from your svelte-routing. It only happens if the route with async <Link> is the initial one to load. If you transition to the route via another link, it doesn't have this issue as the Route isn't in init, it is in flush.
I thought about raising this in svelte-routing (and let me know if I still should), but it is directly related to this context/current_component issue.
Is there any known workaround to this issue other than simply not using context at all?
I'd argue that not using {#await} is a more viable workaround. Context lets you do things not otherwise possible, while {#await} is mostly a convenience over updating certain bits of state when a promise stored in another variable resolves or rejects.
Naive fix:
diff --git a/src/runtime/internal/await_block.ts b/src/runtime/internal/await_block.ts
index 3834ff7c..14f68d5c 100644
--- a/src/runtime/internal/await_block.ts
+++ b/src/runtime/internal/await_block.ts
@@ -1,4 +1,5 @@
import { assign, is_promise } from './utils';
+import { get_current_component, set_current_component } from './lifecycle';
import { check_outros, group_outros, transition_in, transition_out } from './transitions';
import { flush } from './scheduler';
@@ -40,9 +41,12 @@ export function handle_promise(promise, info) {
}
if (is_promise(promise)) {
+ const current_component = get_current_component();
promise.then(value => {
+ set_current_component(current_component);
update(info.then, 1, info.value, value);
}, error => {
+ set_current_component(current_component);
update(info.catch, 2, info.error, error);
});
diff --git a/src/runtime/internal/lifecycle.ts b/src/runtime/internal/lifecycle.ts
index d659fd2e..0ca3e430 100644
--- a/src/runtime/internal/lifecycle.ts
+++ b/src/runtime/internal/lifecycle.ts
@@ -6,7 +6,7 @@ export function set_current_component(component) {
current_component = component;
}
-function get_current_component() {
+export function get_current_component() {
if (!current_component) throw new Error(`Function called outside component initialization`);
return current_component;
}
This doesn't break any existing tests, and at first glance seems to fix the issue here. I have no idea whether this is a good idea.
Fixed in 3.9.1, thanks
Most helpful comment
Naive fix:
This doesn't break any existing tests, and at first glance seems to fix the issue here. I have no idea whether this is a good idea.