DEV: Track RenderGlimmer data on a per-key basis
Previously we were tracking the entire `@data` object. That means a change to any argument would cause everything to be invalidated. This commit changes it so that we track on a per-key basis, so that we reduce unnecessary re-rendering.
This commit is contained in:
parent
cfbfcc7b81
commit
249900f256
|
@ -1,8 +1,8 @@
|
|||
import { hasInternalComponentManager } from "@glimmer/manager";
|
||||
import { tracked } from "@glimmer/tracking";
|
||||
import { setComponentTemplate } from "@ember/component";
|
||||
import templateOnly from "@ember/component/template-only";
|
||||
import { assert } from "@ember/debug";
|
||||
import { TrackedObject } from "@ember-compat/tracked-built-ins";
|
||||
import { createWidgetFrom } from "discourse/widgets/widget";
|
||||
|
||||
const INITIAL_CLASSES = Symbol("RENDER_GLIMMER_INITIAL_CLASSES");
|
||||
|
@ -139,8 +139,22 @@ export default class RenderGlimmer {
|
|||
}
|
||||
|
||||
this._componentInfo = prev._componentInfo;
|
||||
if (prev.data !== this.data) {
|
||||
this._componentInfo.data = this.data;
|
||||
|
||||
const data = this._componentInfo.data;
|
||||
const incomingData = this.data;
|
||||
|
||||
if (incomingData) {
|
||||
const keysToRemove = new Set(Object.keys(data));
|
||||
|
||||
for (let [key, value] of Object.entries(incomingData)) {
|
||||
if (data[key] !== value) {
|
||||
data[key] = value;
|
||||
}
|
||||
keysToRemove.delete(key);
|
||||
}
|
||||
for (const key of keysToRemove) {
|
||||
delete data[key];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -161,7 +175,7 @@ export default class RenderGlimmer {
|
|||
this._componentInfo = new ComponentInfo({
|
||||
element,
|
||||
component,
|
||||
data: this.data,
|
||||
data: new TrackedObject(this.data),
|
||||
setWrapperElementAttrs: (attrs) =>
|
||||
this.updateElementAttrs(element, attrs),
|
||||
});
|
||||
|
@ -231,7 +245,7 @@ export function registerWidgetShim(name, tagName, template) {
|
|||
}
|
||||
|
||||
class ComponentInfo {
|
||||
@tracked data;
|
||||
data;
|
||||
element;
|
||||
component;
|
||||
setWrapperElementAttrs;
|
||||
|
|
|
@ -3,6 +3,7 @@ import templateOnly from "@ember/component/template-only";
|
|||
import { click, fillIn, render } from "@ember/test-helpers";
|
||||
import { hbs } from "ember-cli-htmlbars";
|
||||
import { module, test } from "qunit";
|
||||
import DButton from "discourse/components/d-button";
|
||||
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
|
||||
import { exists, query } from "discourse/tests/helpers/qunit-helpers";
|
||||
import widgetHbs from "discourse/widgets/hbs-compiler";
|
||||
|
@ -61,7 +62,6 @@ class DemoWidget extends Widget {
|
|||
class DemoComponent extends ClassicComponent {
|
||||
static eventLog = [];
|
||||
classNames = ["demo-component"];
|
||||
layout = hbs`<DButton class="component-action-button" @label="component_action" @action={{@action}} /><p class='action-state'>{{@widgetActionTriggered}}</p>`;
|
||||
|
||||
init() {
|
||||
DemoComponent.eventLog.push("init");
|
||||
|
@ -87,6 +87,22 @@ class DemoComponent extends ClassicComponent {
|
|||
super.willDestroy(...arguments);
|
||||
DemoComponent.eventLog.push("willDestroy");
|
||||
}
|
||||
|
||||
@bind
|
||||
logEvent(msg) {
|
||||
DemoComponent.eventLog.push(msg);
|
||||
}
|
||||
|
||||
<template>
|
||||
<DButton
|
||||
class="component-action-button"
|
||||
@label="component_action"
|
||||
@action={{@action}}
|
||||
/>
|
||||
<p class="action-state">{{@widgetActionTriggered}}</p>
|
||||
{{this.logEvent "arg1 rendered" @arg1}}
|
||||
{{this.logEvent "dynamicArg rendered" @dynamicArg}}
|
||||
</template>
|
||||
}
|
||||
|
||||
class ToggleDemoWidget extends Widget {
|
||||
|
@ -207,7 +223,13 @@ module("Integration | Component | Widget | render-glimmer", function (hooks) {
|
|||
|
||||
assert.deepEqual(
|
||||
DemoComponent.eventLog,
|
||||
["init", "didReceiveAttrs", "didInsertElement"],
|
||||
[
|
||||
"init",
|
||||
"didReceiveAttrs",
|
||||
"arg1 rendered",
|
||||
"dynamicArg rendered",
|
||||
"didInsertElement",
|
||||
],
|
||||
"component is initialized correctly"
|
||||
);
|
||||
|
||||
|
@ -217,7 +239,7 @@ module("Integration | Component | Widget | render-glimmer", function (hooks) {
|
|||
await click(".my-widget button");
|
||||
assert.deepEqual(
|
||||
DemoComponent.eventLog,
|
||||
["didReceiveAttrs", "didReceiveAttrs"], // once for input, once for event
|
||||
["didReceiveAttrs", "dynamicArg rendered", "didReceiveAttrs"], // once for input, once for event
|
||||
"component is notified of attr change during widget rerender"
|
||||
);
|
||||
|
||||
|
@ -235,7 +257,13 @@ module("Integration | Component | Widget | render-glimmer", function (hooks) {
|
|||
await fillIn("input.dynamic-value-input", "visibleAgain");
|
||||
assert.deepEqual(
|
||||
DemoComponent.eventLog,
|
||||
["init", "didReceiveAttrs", "didInsertElement"],
|
||||
[
|
||||
"init",
|
||||
"didReceiveAttrs",
|
||||
"arg1 rendered",
|
||||
"dynamicArg rendered",
|
||||
"didInsertElement",
|
||||
],
|
||||
"component can be reinitialized"
|
||||
);
|
||||
});
|
Loading…
Reference in New Issue