Skip to content

Commit 95ebf58

Browse files
authored
Merge pull request #21002 from NullVoxPopuli/nvp/canary/no-render-while-destroying
2 parents d4f7c5c + 19c4444 commit 95ebf58

File tree

2 files changed

+29
-8
lines changed

2 files changed

+29
-8
lines changed

packages/@ember/-internals/glimmer/lib/renderer.ts

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
associateDestroyableChild,
1111
destroy,
1212
isDestroyed,
13+
isDestroying,
1314
registerDestructor,
1415
} from '@glimmer/destroyable';
1516
import { DEBUG } from '@glimmer/env';
@@ -158,8 +159,13 @@ class ComponentRootState {
158159

159160
associateDestroyableChild(this, this.#result);
160161

161-
// override .render function after initial render
162-
this.#render = errorLoopTransaction(() => result.rerender({ alwaysRevalidate: false }));
162+
this.#render = errorLoopTransaction(() => {
163+
if (isDestroying(result) || isDestroyed(result)) return;
164+
165+
return result.rerender({
166+
alwaysRevalidate: false,
167+
});
168+
});
163169
});
164170
}
165171

@@ -228,8 +234,13 @@ class ClassicRootState {
228234

229235
associateDestroyableChild(owner, result);
230236

231-
// override .render function after initial render
232-
this.render = errorLoopTransaction(() => result.rerender({ alwaysRevalidate: false }));
237+
this.render = errorLoopTransaction(() => {
238+
if (isDestroying(result) || isDestroyed(result)) return;
239+
240+
return result.rerender({
241+
alwaysRevalidate: false,
242+
});
243+
});
233244
});
234245
}
235246

packages/@ember/-internals/glimmer/tests/integration/components/render-component-test.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -498,11 +498,21 @@ moduleFor(
498498
* https://github.com/emberjs/rfcs/pull/1099/files#diff-2b962105b9083ca84579cdc957f27f49407440f3c5078083fa369ec18cc46da8R365
499499
*
500500
* We could later add an option to not do this behavior
501+
*
502+
*
503+
* NOTE: for this verify-steps, we only expect foo:3 once, because the first
504+
* incarnation of renderComponent (back when foo was 2) will not run again, due
505+
* to being destroyed.
501506
*/
502-
assert.verifySteps(
503-
[`render:root`, `foo:3`, `foo:3`],
504-
`Destruction is async, so we get an extra 'foo:3' here, and then because our getter consumes foo (since renderComponent is eager), we dirty the cached getter, and re-run the getter, creating a new renderComponent call, overwriting the existing contents`
505-
);
507+
assert.verifySteps([`render:root`, `foo:3`]);
508+
509+
assert.strictEqual(this.element.innerHTML, '<div>3 <button>++</button></div>');
510+
511+
run(() => {
512+
destroy(this.owner);
513+
});
514+
515+
assert.strictEqual(this.element.innerHTML, '');
506516
}
507517

508518
'@test multiple renderComponents share reactivity'() {

0 commit comments

Comments
 (0)