mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
[IMP] component: remove updateState method
This commit is contained in:
+3
-24
@@ -230,12 +230,12 @@ export class Component<
|
||||
}
|
||||
this._patch(vnode);
|
||||
target.appendChild(this.el!);
|
||||
this._observeState();
|
||||
|
||||
if (document.body.contains(target)) {
|
||||
this._visitSubTree(w => {
|
||||
if (!w.__owl__.isMounted && this.el!.contains(w.el)) {
|
||||
w.__owl__.isMounted = true;
|
||||
this._observeState();
|
||||
w.mounted();
|
||||
return true;
|
||||
}
|
||||
@@ -326,25 +326,6 @@ export class Component<
|
||||
return shouldUpdate ? this._updateProps(nextProps) : Promise.resolve();
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the safest update method for widget: its job is to update the state
|
||||
* and rerender (if widget is mounted).
|
||||
*
|
||||
* Notes:
|
||||
* - it checks if we do not add extra keys to the state.
|
||||
* - it is ok to call updateState before the widget is started. In that
|
||||
* case, it will simply update the state and will not rerender
|
||||
*/
|
||||
async updateState(nextState: Partial<State>) {
|
||||
if (Object.keys(nextState).length === 0) {
|
||||
return;
|
||||
}
|
||||
Object.assign(this.state, nextState);
|
||||
if (this.__owl__.isStarted) {
|
||||
await this.render();
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Private
|
||||
//--------------------------------------------------------------------------
|
||||
@@ -418,10 +399,10 @@ export class Component<
|
||||
if (this.__owl__.isMounted) {
|
||||
return;
|
||||
}
|
||||
this._observeState();
|
||||
if (this.__owl__.parent) {
|
||||
if (this.__owl__.parent!.__owl__.isMounted) {
|
||||
this.__owl__.isMounted = true;
|
||||
this._observeState();
|
||||
this.mounted();
|
||||
const children = this.__owl__.children;
|
||||
for (let id in children) {
|
||||
@@ -444,9 +425,7 @@ export class Component<
|
||||
_observeState() {
|
||||
if (Object.keys(this.state).length) {
|
||||
this.__owl__.observer.observe(this.state);
|
||||
this.__owl__.observer.notifyCB = () => {
|
||||
this.render();
|
||||
};
|
||||
this.__owl__.observer.notifyCB = this.render.bind(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+57
-44
@@ -45,14 +45,13 @@ function children(w: Widget): Widget[] {
|
||||
|
||||
// Test widgets
|
||||
class Counter extends Widget {
|
||||
// class Counter extends Widget<WEnv, {}, {counter: number}> {
|
||||
template = "counter";
|
||||
state = {
|
||||
counter: 0
|
||||
};
|
||||
|
||||
inc() {
|
||||
this.updateState({ counter: this.state.counter + 1 });
|
||||
this.state.counter++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,7 +93,7 @@ describe("basic widget properties", () => {
|
||||
expect(target.innerHTML).toBe("<div>0<button>Inc</button></div>");
|
||||
const button = (<HTMLElement>counter.el).getElementsByTagName("button")[0];
|
||||
await button.click();
|
||||
await nextMicroTick();
|
||||
await nextTick();
|
||||
expect(target.innerHTML).toBe("<div>1<button>Inc</button></div>");
|
||||
});
|
||||
|
||||
@@ -109,11 +108,12 @@ describe("basic widget properties", () => {
|
||||
);
|
||||
});
|
||||
|
||||
test("updateState before first render does not trigger a render", async () => {
|
||||
test("changing state before first render does not trigger a render", async () => {
|
||||
let renderCalls = 0;
|
||||
class TestW extends Widget {
|
||||
state = { drinks: 1 };
|
||||
async willStart() {
|
||||
this.updateState({});
|
||||
this.state.drinks++;
|
||||
}
|
||||
async _render() {
|
||||
renderCalls++;
|
||||
@@ -125,15 +125,6 @@ describe("basic widget properties", () => {
|
||||
expect(renderCalls).toBe(1);
|
||||
});
|
||||
|
||||
test("updateState does not allow adding extra keys", async () => {
|
||||
const widget = new Widget(env);
|
||||
try {
|
||||
await widget.updateState({ extra: 1 });
|
||||
} catch (e) {
|
||||
expect(e.message).toMatch("Invalid key:");
|
||||
}
|
||||
});
|
||||
|
||||
test("keeps a reference to env", async () => {
|
||||
const widget = new Widget(env);
|
||||
expect(widget.env).toBe(env);
|
||||
@@ -317,7 +308,8 @@ describe("lifecycle hooks", () => {
|
||||
const widget = new ParentWidget(env);
|
||||
await widget.mount(fixture);
|
||||
expect(steps).toEqual(["init", "willstart", "mounted"]);
|
||||
await widget.updateState({ ok: false });
|
||||
widget.state.ok = false;
|
||||
await nextTick();
|
||||
expect(steps).toEqual(["init", "willstart", "mounted", "willunmount"]);
|
||||
});
|
||||
|
||||
@@ -329,7 +321,7 @@ describe("lifecycle hooks", () => {
|
||||
childUnmounted = true;
|
||||
}
|
||||
increment() {
|
||||
this.updateState({ n: this.state.n + 1 });
|
||||
this.state += 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -343,10 +335,10 @@ describe("lifecycle hooks", () => {
|
||||
</div>`;
|
||||
state = { n: 0, flag: true };
|
||||
increment() {
|
||||
this.updateState({ n: this.state.n + 1 });
|
||||
this.state.n += 1;
|
||||
}
|
||||
toggleSubWidget() {
|
||||
this.updateState({ flag: !this.state.flag });
|
||||
this.state.flag = !this.state.flag;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -433,7 +425,7 @@ describe("lifecycle hooks", () => {
|
||||
expect(fixture.innerHTML).toBe("<span>2</span>");
|
||||
});
|
||||
|
||||
test("patched hook is called after updateState", async () => {
|
||||
test("patched hook is called after updating State", async () => {
|
||||
let n = 0;
|
||||
|
||||
class TestWidget extends Widget {
|
||||
@@ -447,10 +439,12 @@ describe("lifecycle hooks", () => {
|
||||
await widget.mount(fixture);
|
||||
expect(n).toBe(0);
|
||||
|
||||
await widget.updateState({}); // empty update, should do nothing
|
||||
widget.state.a = 1; // empty update, should do nothing
|
||||
await nextTick();
|
||||
expect(n).toBe(0);
|
||||
|
||||
await widget.updateState({ a: 3 });
|
||||
widget.state.a = 3;
|
||||
await nextTick();
|
||||
expect(n).toBe(1);
|
||||
});
|
||||
|
||||
@@ -533,10 +527,11 @@ describe("lifecycle hooks", () => {
|
||||
await widget.mount(fixture);
|
||||
expect(created).toBe(false);
|
||||
expect(mounted).toBe(false);
|
||||
await widget.updateState({ flag: true });
|
||||
|
||||
widget.state.flag = true;
|
||||
await nextTick();
|
||||
expect(mounted).toBe(true);
|
||||
expect(created).toBe(true);
|
||||
await widget.updateState({ flag: false });
|
||||
});
|
||||
|
||||
test("willPatch/patched hook", async () => {
|
||||
@@ -674,7 +669,7 @@ describe("composition", () => {
|
||||
);
|
||||
const button = fixture.getElementsByTagName("button")[0];
|
||||
await button.click();
|
||||
await nextMicroTick();
|
||||
await nextTick();
|
||||
expect(fixture.innerHTML).toBe(
|
||||
"<div><div>1<button>Inc</button></div></div>"
|
||||
);
|
||||
@@ -709,7 +704,7 @@ describe("composition", () => {
|
||||
await widget.mount(fixture);
|
||||
const button = fixture.getElementsByTagName("button")[0];
|
||||
await button.click();
|
||||
await nextMicroTick();
|
||||
await nextTick();
|
||||
expect(fixture.innerHTML).toBe(
|
||||
"<div><div>1<button>Inc</button></div></div>"
|
||||
);
|
||||
@@ -729,13 +724,16 @@ describe("composition", () => {
|
||||
await widget.mount(fixture);
|
||||
const button = fixture.getElementsByTagName("button")[0];
|
||||
await button.click();
|
||||
await nextMicroTick();
|
||||
await nextTick();
|
||||
expect(fixture.innerHTML).toBe(
|
||||
"<div><div>1<button>Inc</button></div></div>"
|
||||
);
|
||||
await widget.updateState({ ok: false });
|
||||
widget.state.ok = false;
|
||||
await nextTick();
|
||||
expect(fixture.innerHTML).toBe("<div></div>");
|
||||
await widget.updateState({ ok: true });
|
||||
|
||||
widget.state.ok = true;
|
||||
await nextTick();
|
||||
expect(fixture.innerHTML).toBe(
|
||||
"<div><div>0<button>Inc</button></div></div>"
|
||||
);
|
||||
@@ -751,16 +749,20 @@ describe("composition", () => {
|
||||
await widget.mount(fixture);
|
||||
const button = fixture.getElementsByTagName("button")[0];
|
||||
await button.click();
|
||||
await nextMicroTick();
|
||||
await nextTick();
|
||||
expect(fixture.innerHTML).toBe(
|
||||
"<div><div>1<button>Inc</button></div></div>"
|
||||
);
|
||||
const counter = children(widget)[0];
|
||||
expect(counter.__owl__.isMounted).toBe(true);
|
||||
await widget.updateState({ ok: false });
|
||||
|
||||
widget.state.ok = false;
|
||||
await nextTick();
|
||||
expect(fixture.innerHTML).toBe("<div></div>");
|
||||
expect(counter.__owl__.isMounted).toBe(false);
|
||||
await widget.updateState({ ok: true });
|
||||
|
||||
widget.state.ok = true;
|
||||
await nextTick();
|
||||
expect(counter.__owl__.isMounted).toBe(true);
|
||||
expect(fixture.innerHTML).toBe(
|
||||
"<div><div>1<button>Inc</button></div></div>"
|
||||
@@ -780,9 +782,12 @@ describe("composition", () => {
|
||||
await widget.mount(fixture);
|
||||
const input = fixture.getElementsByTagName("input")[0];
|
||||
input.value = "test";
|
||||
await widget.updateState({ ok: false });
|
||||
widget.state.ok = false;
|
||||
await nextTick();
|
||||
expect(fixture.innerHTML).toBe("<div></div>");
|
||||
await widget.updateState({ ok: true });
|
||||
|
||||
widget.state.ok = true;
|
||||
await nextTick();
|
||||
expect(fixture.innerHTML).toBe("<div><input></div>");
|
||||
const input2 = fixture.getElementsByTagName("input")[0];
|
||||
expect(input).toBe(input2);
|
||||
@@ -847,7 +852,8 @@ describe("composition", () => {
|
||||
}
|
||||
const parent = new Parent(env);
|
||||
await parent.mount(fixture);
|
||||
await parent.updateState({ numbers: [1, 3] });
|
||||
parent.state.numbers = [1, 3];
|
||||
await nextTick();
|
||||
expect(normalize(fixture.innerHTML)).toBe(
|
||||
normalize(`
|
||||
<div>
|
||||
@@ -878,7 +884,9 @@ describe("composition", () => {
|
||||
const parent = new Parent(env);
|
||||
await parent.mount(fixture);
|
||||
const child = children(parent)[0];
|
||||
await parent.updateState({ flag: true });
|
||||
|
||||
parent.state.flag = true;
|
||||
await nextTick();
|
||||
expect(children(parent)[0]).toBe(child);
|
||||
expect(child.__owl__.isDestroyed).toBe(false);
|
||||
expect(normalize(fixture.innerHTML)).toBe(
|
||||
@@ -1013,10 +1021,12 @@ describe("other directives with t-widget", () => {
|
||||
|
||||
expect(fixture.innerHTML).toBe("<div><span>hey</span></div>");
|
||||
|
||||
await widget.updateState({ flag: false });
|
||||
widget.state.flag = false;
|
||||
await nextTick();
|
||||
expect(fixture.innerHTML).toBe("<div></div>");
|
||||
|
||||
await widget.updateState({ flag: true });
|
||||
widget.state.flag = true;
|
||||
await nextTick();
|
||||
expect(fixture.innerHTML).toBe("<div><span>hey</span></div>");
|
||||
});
|
||||
|
||||
@@ -1039,7 +1049,8 @@ describe("other directives with t-widget", () => {
|
||||
|
||||
expect(normalize(fixture.innerHTML)).toBe("<div><div>somediv</div></div>");
|
||||
|
||||
await widget.updateState({ flag: false });
|
||||
widget.state.flag = false;
|
||||
await nextTick();
|
||||
expect(normalize(fixture.innerHTML)).toBe("<div><span>hey</span></div>");
|
||||
});
|
||||
|
||||
@@ -1062,7 +1073,8 @@ describe("other directives with t-widget", () => {
|
||||
|
||||
expect(normalize(fixture.innerHTML)).toBe("<div><div>somediv</div></div>");
|
||||
|
||||
await widget.updateState({ flag: false });
|
||||
widget.state.flag = false;
|
||||
await nextTick();
|
||||
expect(normalize(fixture.innerHTML)).toBe("<div><span>hey</span></div>");
|
||||
});
|
||||
});
|
||||
@@ -1098,7 +1110,8 @@ describe("random stuff/miscellaneous", () => {
|
||||
const widget = new Parent(env);
|
||||
await widget.mount(fixture);
|
||||
expect(fixture.innerHTML).toBe("<div><span>abc</span></div>");
|
||||
await widget.updateState({ flag: true });
|
||||
widget.state.flag = true;
|
||||
await nextTick();
|
||||
expect(fixture.innerHTML).toBe("<div><span>abcdef</span></div>");
|
||||
});
|
||||
|
||||
@@ -1225,10 +1238,10 @@ describe("async rendering", () => {
|
||||
const parent = new Parent(env);
|
||||
await parent.mount(fixture);
|
||||
expect(fixture.innerHTML.replace(/\r?\n|\r|\s+/g, "")).toBe("<div></div>");
|
||||
parent.updateState({ flagA: true });
|
||||
parent.state.flagA = true;
|
||||
await nextTick();
|
||||
expect(fixture.innerHTML.replace(/\r?\n|\r|\s+/g, "")).toBe("<div></div>");
|
||||
parent.updateState({ flagB: true });
|
||||
parent.state.flagB = true;
|
||||
await nextTick();
|
||||
expect(fixture.innerHTML.replace(/\r?\n|\r|\s+/g, "")).toBe("<div></div>");
|
||||
defB.resolve();
|
||||
@@ -1271,12 +1284,12 @@ describe("async rendering", () => {
|
||||
expect(fixture.innerHTML.replace(/\r?\n|\r|\s+/g, "")).toBe(
|
||||
"<div><span>a1</span></div>"
|
||||
);
|
||||
parent.updateState({ valA: 2 });
|
||||
parent.state.valA = 2;
|
||||
await nextTick();
|
||||
expect(fixture.innerHTML.replace(/\r?\n|\r|\s+/g, "")).toBe(
|
||||
"<div><span>a1</span></div>"
|
||||
);
|
||||
parent.updateState({ flagB: true });
|
||||
parent.state.flagB = true;
|
||||
await nextTick();
|
||||
expect(fixture.innerHTML.replace(/\r?\n|\r|\s+/g, "")).toBe(
|
||||
"<div><span>a1</span></div>"
|
||||
|
||||
+12
-6
@@ -406,7 +406,8 @@ describe("connecting a component to store", () => {
|
||||
await parent.mount(fixture);
|
||||
expect(steps).toEqual(["child:mounted"]);
|
||||
|
||||
await parent.updateState({ child: false });
|
||||
parent.state.child = false;
|
||||
await nextTick();
|
||||
expect(steps).toEqual(["child:mounted", "child:willUnmount"]);
|
||||
});
|
||||
|
||||
@@ -479,7 +480,8 @@ describe("connecting a component to store", () => {
|
||||
await app.mount(fixture);
|
||||
expect(fixture.innerHTML).toBe("<div><span>jupiler</span></div>");
|
||||
|
||||
await app.updateState({ beerId: 2 });
|
||||
app.state.beerId = 2;
|
||||
await nextTick();
|
||||
expect(fixture.innerHTML).toBe("<div><span>kwak</span></div>");
|
||||
});
|
||||
|
||||
@@ -562,7 +564,8 @@ describe("connecting a component to store", () => {
|
||||
"<div><div><span>taster:aaron</span></div></div>"
|
||||
);
|
||||
|
||||
await app.updateState({ beerId: 1 });
|
||||
app.state.beerId = 1;
|
||||
await nextTick();
|
||||
expect(fixture.innerHTML).toBe(
|
||||
"<div><div><span>taster:aaron</span><span>selected:jupiler</span></div></div>"
|
||||
);
|
||||
@@ -573,7 +576,8 @@ describe("connecting a component to store", () => {
|
||||
"<div><div><span>taster:aaron</span><span>selected:jupiler</span><span>consumed:jupiler</span></div></div>"
|
||||
);
|
||||
|
||||
await app.updateState({ beerId: 0 });
|
||||
app.state.beerId = 0;
|
||||
await nextTick();
|
||||
expect(fixture.innerHTML).toBe(
|
||||
"<div><div><span>taster:aaron</span><span>consumed:jupiler</span></div></div>"
|
||||
);
|
||||
@@ -630,7 +634,8 @@ describe("connecting a component to store", () => {
|
||||
"<div><div><span>taster:aaron</span></div></div>"
|
||||
);
|
||||
|
||||
await app.updateState({ beerId: 1 });
|
||||
app.state.beerId = 1;
|
||||
await nextTick();
|
||||
expect(fixture.innerHTML).toBe(
|
||||
"<div><div><span>taster:aaron</span><span>selected:jupiler</span></div></div>"
|
||||
);
|
||||
@@ -647,7 +652,8 @@ describe("connecting a component to store", () => {
|
||||
"<div><div><span>taster:aaron</span><span>selected:kwak</span><span>consumed:kwak</span></div></div>"
|
||||
);
|
||||
|
||||
await app.updateState({ beerId: 0 });
|
||||
app.state.beerId = 0;
|
||||
await nextTick();
|
||||
expect(fixture.innerHTML).toBe(
|
||||
"<div><div><span>taster:aaron</span><span>consumed:kwak</span></div></div>"
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user