-
-
Notifications
You must be signed in to change notification settings - Fork 4.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[fix] bind:this works during onMount callback in manually-created component #6920
[fix] bind:this works during onMount callback in manually-created component #6920
Conversation
If a component was instantiated with new Component(), its onMount callback was being called before the bind:this bindings were set up, so that the binding variable was undefined. Now the bind:this bindings are properly bound before the onMount callbacks are called.
BTW, the current behavior of |
I can fix the three diff --git a/src/runtime/internal/scheduler.ts b/src/runtime/internal/scheduler.ts
index cc93a6af5..fd69256a7 100644
--- a/src/runtime/internal/scheduler.ts
+++ b/src/runtime/internal/scheduler.ts
@@ -1,5 +1,6 @@
import { run_all, Queue } from './utils';
import { set_current_component } from './lifecycle';
+import { get_current_component } from '.';
export const dirty_components = new Queue<any>();
export const intros = { enabled: false };
@@ -37,12 +38,16 @@ export function flush() {
do {
// first, call beforeUpdate functions
// and update components
+ let current_component = null;
+ try {
+ current_component = get_current_component()
+ } catch {}
while (dirty_components.length) {
const component = dirty_components.shift();
set_current_component(component);
update(component.$$);
}
- set_current_component(null);
+ set_current_component(current_component);
dirty_components.length = 0;
The behavior of resetting the current component to
So if we make Paging @tanhauhau who can help me understand why #6564 fails when |
Found a way to make all the unit tests pass, by moving the "save and restore current component" outside the do ... while loop so that it only runs once. This seems to fulfill all the requirements of the previous work on the
Reasons why undoing the
This should be ready for someone to review and merge now. |
While I wait for a Svelte team member to have time to review this, a couple words about the Queue implementation. I chose to go with a deliberately minimal implementation, with only the bare minimum features needed to fulfill the needs of the |
Found a way to make it work without changing the dirty components array into a queue structure, reducing bundle size.
Inside flush(), we don't care if there is a current component or not, we just want to save and restore it if there is one. Rather than throwing and catching an error that would happen often, we'll just create another version of get_current_component() that doesn't throw.
One unit test timed out after 15 minutes, apparently because the test runner got stuck. I don't have the access rights to re-run the tests. Could someone push the "Re-run all checks" button for me? Or I could push a meaningless rebase to force the tests to re-run, but that seems a little silly. |
We basically just ignore it if it's only a single job failing since the tests are known to be flaky |
1540f70
to
4e48481
Compare
Good to know. Turned out I'd accidentally missed removing one blank line when I removed the code block above it, so I did end up pushing a commit making no code changes, which ended up re-running all the unit tests. And then one of the Mac test runners had a browser that died, which cancelled seven different jobs. So it ended up being a bit of a moot point, because I did have to do a Now that I've simplified the code by removing the Queue implementation (thanks to the good suggestion @dummdidumm made), I think most of this PR will be easy to approve. There are two points remaining that I'd like someone to weigh in on:
Pros and cons of the ways to save and restore the current component:
|
4e48481
to
707908b
Compare
There shouldn't really be a blank line between the opening brace of a function and its first line of code. Let's get rid of it.
707908b
to
195aed1
Compare
Thanks for your work on this, and especially for laying out your thought process this clearly. My opinion on your questions:
In general, while we're at it, this specific method could use some more comments in my opinion. I feel like you looked at this function from all angles by now and can probably confidently add some comments explaining why things are done the way, for example that flush can be reentrant (and why), why the index needs to be tracked outside of the functions, etc. |
Since it's not necessary to restore the saved value of current_component before calling the flush_callbacks list, we'll move the restore to the very end of the function, which makes sense as saving it is the first thing the function does.
As requested during code review, here's an extensive list of comments explaining the flush() function in more detail for future maintainers.
@dummdidumm wrote:
Done in commit fd7586c. Let me know if that's a bit too much and I'll trim the comments down a little. |
Pulled #6858's unit tests into my branch and ran them, and my changes do not fix the bugs that #6858 fixes, where So both this PR and #6858 are needed as they fix different issues. Whichever one is merged first will cause a merge conflict in the other one, but they should be simple enough to resolve. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the comment! By now (and through the comment) I think I understood enough of this part to give my approval on this PR 👍 If this one's merged, you could then look at the other PR you mentioned since you are already so familiar with that part, if you like.
Co-authored-by: Bjorn Lu <bjornlu.dev@gmail.com>
If a component was instantiated with new Component(), its onMount callback was being called before the bind:this bindings were set up, so that the binding variable was undefined. Now the bind:this bindings are properly bound before the onMount callbacks are called.
Fixes #6760.
Fixes #6919.
Before submitting the PR, please make sure you do the following
[feat]
,[fix]
,[chore]
, or[docs]
.Tests
npm test
and lint the project withnpm run lint
Note that while this change makes the regression test I added (reproducing #6760 and #6919) pass, it makes the following tests fail:await-catch-no-expression
await-then-catch-multiple
await-then-no-expression
Somehow these tests are dependent on the current behavior offlush()
that is causing #6760 and #6919. I have not yet found a way to fix those two issues and still have those threeawait
-related tests pass, so I would need a little help figuring that out.Update: All tests are passing now. This is ready to be reviewed and merged.