cleanup, rename setState into updateState

This commit is contained in:
Géry Debongnie
2019-03-19 10:05:46 +01:00
parent 7d10e57cc0
commit 695636e60e
11 changed files with 61 additions and 60 deletions
+1 -1
View File
@@ -24,7 +24,7 @@ export class Counter extends Component {
} }
increment(delta) { increment(delta) {
this.setState({ counter: this.state.counter + delta }); this.updateState({ counter: this.state.counter + delta });
} }
} }
``` ```
+2 -2
View File
@@ -36,7 +36,7 @@ export class App extends odoo.core.Component {
} }
setMessageCount(n) { setMessageCount(n) {
this.setState({ this.updateState({
messages: messages.slice(0, n) messages: messages.slice(0, n)
}); });
} }
@@ -45,7 +45,7 @@ export class App extends odoo.core.Component {
const index = messages.findIndex(m => m.id === data.id); const index = messages.findIndex(m => m.id === data.id);
const n = this.state.messages.length; const n = this.state.messages.length;
messages.splice(index, 1); messages.splice(index, 1);
this.setState({ messages: messages.slice(0, n - 1) }); this.updateState({ messages: messages.slice(0, n - 1) });
} }
increment(delta) { increment(delta) {
+1 -1
View File
@@ -13,6 +13,6 @@ export class Counter extends odoo.core.Component {
} }
increment(delta) { increment(delta) {
this.setState({ counter: this.state.counter + delta }); this.updateState({ counter: this.state.counter + delta });
} }
} }
+1 -1
View File
@@ -33,7 +33,7 @@ export class Clock extends Widget<{}, State> {
} }
updateTime() { updateTime() {
this.setState({ currentTime: new Date().toLocaleTimeString() }); this.updateState({ currentTime: new Date().toLocaleTimeString() });
} }
startClock() { startClock() {
@@ -34,6 +34,6 @@ export class Counter extends Widget<Props, State> {
} }
increment(delta: number) { increment(delta: number) {
this.setState({ counter: this.state.counter + delta }); this.updateState({ counter: this.state.counter + delta });
} }
} }
@@ -22,25 +22,25 @@ export class Discuss extends Widget<{}, State> {
resetCounter(ev: MouseEvent) { resetCounter(ev: MouseEvent) {
if (this.refs.counter instanceof Counter) { if (this.refs.counter instanceof Counter) {
this.refs.counter.setState({ counter: 3 }); this.refs.counter.updateState({ counter: 3 });
} }
} }
resetCounterAsync(ev: MouseEvent) { resetCounterAsync(ev: MouseEvent) {
setTimeout(() => { setTimeout(() => {
if (this.refs.counter2 instanceof Counter) { if (this.refs.counter2 instanceof Counter) {
this.refs.counter2.setState({ counter: 300 }); this.refs.counter2.updateState({ counter: 300 });
} }
}, 3000); }, 3000);
} }
toggle() { toggle() {
this.setState({ validcounter: !this.state.validcounter }); this.updateState({ validcounter: !this.state.validcounter });
} }
toggleColor() { toggleColor() {
const newColor = this.state.color === "red" ? "blue" : "red"; const newColor = this.state.color === "red" ? "blue" : "red";
this.setState({ color: newColor }); this.updateState({ color: newColor });
} }
addNotif(sticky: boolean) { addNotif(sticky: boolean) {
+1 -1
View File
@@ -24,7 +24,7 @@ export class Root extends Widget<Store, State> {
} }
mounted() { mounted() {
this.store.on("state_updated", this, this.setState); this.store.on("state_updated", this, this.updateState);
this.store.on("rpc_status", this, this.toggleLoadingIndicator); this.store.on("rpc_status", this, this.toggleLoadingIndicator);
this.store.on("update_action", this, this.applyController); this.store.on("update_action", this, this.applyController);
if (this.store.lastController) { if (this.store.lastController) {
+2 -2
View File
@@ -28,10 +28,10 @@ export class PureWidget<P, S> extends Widget<P, S> {
} }
return false; return false;
} }
async setState(nextState: Partial<S>) { async updateState(nextState: Partial<S>) {
for (let k in nextState) { for (let k in nextState) {
if (nextState[k] !== this.state[k]) { if (nextState[k] !== this.state[k]) {
return super.setState(nextState); return super.updateState(nextState);
} }
} }
} }
+1 -1
View File
@@ -114,7 +114,7 @@
<button t-on-click="resetCounterAsync">Reset counter 2 in 3s</button> <button t-on-click="resetCounterAsync">Reset counter 2 in 3s</button>
<button t-on-click="toggle">Toggle Clock/counters</button> <button t-on-click="toggle">Toggle Clock/counters</button>
<button t-on-click="toggleColor">Toggle Color</button> <button t-on-click="toggleColor">Toggle Color</button>
<button t-on-click="setState({})">Rerender this widget</button> <button t-on-click="updateState({})">Rerender this widget</button>
<input t-ref="textinput"/> <input t-ref="textinput"/>
<t t-if="state.validcounter"> <t t-if="state.validcounter">
<t t-widget="Counter" t-ref="counter" t-props="{initialState:4}"/> <t t-widget="Counter" t-ref="counter" t-props="{initialState:4}"/>
+22 -21
View File
@@ -108,10 +108,6 @@ export class Component<
mounted() {} mounted() {}
shouldUpdate(nextProps: Props): boolean {
return true;
}
willUnmount() {} willUnmount() {}
destroyed() {} destroyed() {}
@@ -136,6 +132,7 @@ export class Component<
target.appendChild(child.el!); target.appendChild(child.el!);
child.__mount(); child.__mount();
} }
async mount(target: HTMLElement): Promise<void> { async mount(target: HTMLElement): Promise<void> {
const vnode = await this._start(); const vnode = await this._start();
if (this.__widget__.isDestroyed) { if (this.__widget__.isDestroyed) {
@@ -195,23 +192,8 @@ export class Component<
} }
} }
/** shouldUpdate(nextProps: Props): boolean {
* This is the safest update method for widget: its job is to update the state return true;
* and rerender (if widget is mounted).
*
* Notes:
* - it checks if we do not add extra keys to the state.
* - it is ok to call setState before the widget is started. In that
* case, it will simply update the state and will not rerender
*/
async setState(nextState: Partial<State>) {
if (Object.keys(nextState).length === 0) {
return;
}
Object.assign(this.state, nextState);
if (this.__widget__.isStarted) {
return this.render();
}
} }
async updateProps(nextProps: Props): Promise<void> { async updateProps(nextProps: Props): Promise<void> {
@@ -223,6 +205,25 @@ export class Component<
return shouldUpdate ? this._updateProps(nextProps) : Promise.resolve(); 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.__widget__.isStarted) {
return this.render();
}
}
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
// Private // Private
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
+25 -25
View File
@@ -52,7 +52,7 @@ class Counter extends Widget {
}; };
inc() { inc() {
this.setState({ counter: this.state.counter + 1 }); this.updateState({ counter: this.state.counter + 1 });
} }
} }
@@ -103,11 +103,11 @@ describe("basic widget properties", () => {
); );
}); });
test("setState before first render does not trigger a render", async () => { test("updateState before first render does not trigger a render", async () => {
let renderCalls = 0; let renderCalls = 0;
class TestW extends Widget { class TestW extends Widget {
async willStart() { async willStart() {
this.setState({}); this.updateState({});
} }
async _render() { async _render() {
renderCalls++; renderCalls++;
@@ -119,10 +119,10 @@ describe("basic widget properties", () => {
expect(renderCalls).toBe(1); expect(renderCalls).toBe(1);
}); });
test("setState does not allow adding extra keys", async () => { test("updateState does not allow adding extra keys", async () => {
const widget = new Widget(env); const widget = new Widget(env);
try { try {
await widget.setState({ extra: 1 }); await widget.updateState({ extra: 1 });
} catch (e) { } catch (e) {
expect(e.message).toMatch("Invalid key:"); expect(e.message).toMatch("Invalid key:");
} }
@@ -253,7 +253,7 @@ describe("lifecycle hooks", () => {
const widget = new ParentWidget(env); const widget = new ParentWidget(env);
await widget.mount(fixture); await widget.mount(fixture);
expect(hookCounter).toBe(0); // sub widget not created yet expect(hookCounter).toBe(0); // sub widget not created yet
await widget.setState({ ok: true }); await widget.updateState({ ok: true });
expect(hookCounter).toBe(2); expect(hookCounter).toBe(2);
}); });
@@ -313,7 +313,7 @@ describe("lifecycle hooks", () => {
const widget = new ParentWidget(env); const widget = new ParentWidget(env);
await widget.mount(fixture); await widget.mount(fixture);
expect(steps).toEqual(["init", "willstart", "mounted"]); expect(steps).toEqual(["init", "willstart", "mounted"]);
await widget.setState({ ok: false }); await widget.updateState({ ok: false });
expect(steps).toEqual([ expect(steps).toEqual([
"init", "init",
"willstart", "willstart",
@@ -568,9 +568,9 @@ describe("composition", () => {
expect(fixture.innerHTML).toBe( expect(fixture.innerHTML).toBe(
"<div><div>1<button>Inc</button></div></div>" "<div><div>1<button>Inc</button></div></div>"
); );
await widget.setState({ ok: false }); await widget.updateState({ ok: false });
expect(fixture.innerHTML).toBe("<div></div>"); expect(fixture.innerHTML).toBe("<div></div>");
await widget.setState({ ok: true }); await widget.updateState({ ok: true });
expect(fixture.innerHTML).toBe( expect(fixture.innerHTML).toBe(
"<div><div>0<button>Inc</button></div></div>" "<div><div>0<button>Inc</button></div></div>"
); );
@@ -592,10 +592,10 @@ describe("composition", () => {
); );
const counter = children(widget)[0]; const counter = children(widget)[0];
expect(counter.__widget__.isMounted).toBe(true); expect(counter.__widget__.isMounted).toBe(true);
await widget.setState({ ok: false }); await widget.updateState({ ok: false });
expect(fixture.innerHTML).toBe("<div></div>"); expect(fixture.innerHTML).toBe("<div></div>");
expect(counter.__widget__.isMounted).toBe(false); expect(counter.__widget__.isMounted).toBe(false);
await widget.setState({ ok: true }); await widget.updateState({ ok: true });
expect(counter.__widget__.isMounted).toBe(true); expect(counter.__widget__.isMounted).toBe(true);
expect(fixture.innerHTML).toBe( expect(fixture.innerHTML).toBe(
"<div><div>1<button>Inc</button></div></div>" "<div><div>1<button>Inc</button></div></div>"
@@ -615,9 +615,9 @@ describe("composition", () => {
await widget.mount(fixture); await widget.mount(fixture);
const input = fixture.getElementsByTagName("input")[0]; const input = fixture.getElementsByTagName("input")[0];
input.value = "test"; input.value = "test";
await widget.setState({ ok: false }); await widget.updateState({ ok: false });
expect(fixture.innerHTML).toBe("<div></div>"); expect(fixture.innerHTML).toBe("<div></div>");
await widget.setState({ ok: true }); await widget.updateState({ ok: true });
expect(fixture.innerHTML).toBe("<div><input></div>"); expect(fixture.innerHTML).toBe("<div><input></div>");
const input2 = fixture.getElementsByTagName("input")[0]; const input2 = fixture.getElementsByTagName("input")[0];
expect(input).toBe(input2); expect(input).toBe(input2);
@@ -682,7 +682,7 @@ describe("composition", () => {
} }
const parent = new Parent(env); const parent = new Parent(env);
await parent.mount(fixture); await parent.mount(fixture);
await parent.setState({ numbers: [1, 3] }); await parent.updateState({ numbers: [1, 3] });
expect(normalize(fixture.innerHTML)).toBe( expect(normalize(fixture.innerHTML)).toBe(
normalize(` normalize(`
<div> <div>
@@ -713,7 +713,7 @@ describe("composition", () => {
const parent = new Parent(env); const parent = new Parent(env);
await parent.mount(fixture); await parent.mount(fixture);
const child = children(parent)[0]; const child = children(parent)[0];
await parent.setState({ flag: true }); await parent.updateState({ flag: true });
expect(children(parent)[0]).toBe(child); expect(children(parent)[0]).toBe(child);
expect(child.__widget__.isDestroyed).toBe(false); expect(child.__widget__.isDestroyed).toBe(false);
expect(normalize(fixture.innerHTML)).toBe( expect(normalize(fixture.innerHTML)).toBe(
@@ -848,10 +848,10 @@ describe("other directives with t-widget", () => {
expect(fixture.innerHTML).toBe("<div><span>hey</span></div>"); expect(fixture.innerHTML).toBe("<div><span>hey</span></div>");
await widget.setState({ flag: false }); await widget.updateState({ flag: false });
expect(fixture.innerHTML).toBe("<div></div>"); expect(fixture.innerHTML).toBe("<div></div>");
await widget.setState({ flag: true }); await widget.updateState({ flag: true });
expect(fixture.innerHTML).toBe("<div><span>hey</span></div>"); expect(fixture.innerHTML).toBe("<div><span>hey</span></div>");
}); });
@@ -874,7 +874,7 @@ describe("other directives with t-widget", () => {
expect(normalize(fixture.innerHTML)).toBe("<div><div>somediv</div></div>"); expect(normalize(fixture.innerHTML)).toBe("<div><div>somediv</div></div>");
await widget.setState({ flag: false }); await widget.updateState({ flag: false });
expect(normalize(fixture.innerHTML)).toBe("<div><span>hey</span></div>"); expect(normalize(fixture.innerHTML)).toBe("<div><span>hey</span></div>");
}); });
}); });
@@ -910,7 +910,7 @@ describe("random stuff/miscellaneous", () => {
const widget = new Parent(env); const widget = new Parent(env);
await widget.mount(fixture); await widget.mount(fixture);
expect(fixture.innerHTML).toBe("<div><span>abc</span></div>"); expect(fixture.innerHTML).toBe("<div><span>abc</span></div>");
await widget.setState({ flag: true }); await widget.updateState({ flag: true });
expect(fixture.innerHTML).toBe("<div><span>abcdef</span></div>"); expect(fixture.innerHTML).toBe("<div><span>abcdef</span></div>");
}); });
@@ -979,10 +979,10 @@ describe("async rendering", () => {
const w = new W(env); const w = new W(env);
await w.mount(fixture); await w.mount(fixture);
expect(n).toBe(0); expect(n).toBe(0);
w.setState({ val: 2 }); w.updateState({ val: 2 });
expect(n).toBe(1); expect(n).toBe(1);
await nextTick(); await nextTick();
w.setState({ val: 3 }); w.updateState({ val: 3 });
expect(n).toBe(2); expect(n).toBe(2);
def.resolve(); def.resolve();
await nextTick(); await nextTick();
@@ -1019,10 +1019,10 @@ describe("async rendering", () => {
const parent = new Parent(env); const parent = new Parent(env);
await parent.mount(fixture); await parent.mount(fixture);
expect(fixture.innerHTML.replace(/\r?\n|\r|\s+/g, "")).toBe("<div></div>"); expect(fixture.innerHTML.replace(/\r?\n|\r|\s+/g, "")).toBe("<div></div>");
parent.setState({ flagA: true }); parent.updateState({ flagA: true });
await nextTick(); await nextTick();
expect(fixture.innerHTML.replace(/\r?\n|\r|\s+/g, "")).toBe("<div></div>"); expect(fixture.innerHTML.replace(/\r?\n|\r|\s+/g, "")).toBe("<div></div>");
parent.setState({ flagB: true }); parent.updateState({ flagB: true });
await nextTick(); await nextTick();
expect(fixture.innerHTML.replace(/\r?\n|\r|\s+/g, "")).toBe("<div></div>"); expect(fixture.innerHTML.replace(/\r?\n|\r|\s+/g, "")).toBe("<div></div>");
defB.resolve(); defB.resolve();
@@ -1065,12 +1065,12 @@ describe("async rendering", () => {
expect(fixture.innerHTML.replace(/\r?\n|\r|\s+/g, "")).toBe( expect(fixture.innerHTML.replace(/\r?\n|\r|\s+/g, "")).toBe(
"<div><span>a1</span></div>" "<div><span>a1</span></div>"
); );
parent.setState({ valA: 2 }); parent.updateState({ valA: 2 });
await nextTick(); await nextTick();
expect(fixture.innerHTML.replace(/\r?\n|\r|\s+/g, "")).toBe( expect(fixture.innerHTML.replace(/\r?\n|\r|\s+/g, "")).toBe(
"<div><span>a1</span></div>" "<div><span>a1</span></div>"
); );
parent.setState({ flagB: true }); parent.updateState({ flagB: true });
await nextTick(); await nextTick();
expect(fixture.innerHTML.replace(/\r?\n|\r|\s+/g, "")).toBe( expect(fixture.innerHTML.replace(/\r?\n|\r|\s+/g, "")).toBe(
"<div><span>a1</span></div>" "<div><span>a1</span></div>"