mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
[FIX] ConnectedComponent: keep props uptodate
This is a tricky bug. The problem is that a ConnectedComponent can trigger a rendering before it is aware that there is a state change in the store, and just before the store update event comes in. What we do in this commit is to update the storeProps whenever a rendering is scheduled. However, we need to keep the rendering information as a promise to give it in some case to the __checkUpdate method (see the note in the render method) closes #268
This commit is contained in:
@@ -15,3 +15,7 @@ exports[`connecting a component to store deep and shallow connecting a component
|
||||
exports[`connecting a component to store deep and shallow connecting a component 3`] = `"<div><span>Bertinchamps</span></div>"`;
|
||||
|
||||
exports[`connecting a component to store deep and shallow connecting a component 4`] = `"<div><span>Kasteel</span></div>"`;
|
||||
|
||||
exports[`various scenarios scenarios with async store updates and some components events 1`] = `"<div><button>Do stuff</button><div><span>Attachment 100</span><span>Name: text.txt</span></div></div>"`;
|
||||
|
||||
exports[`various scenarios scenarios with async store updates and some components events 2`] = `"<div><button>Do stuff</button></div>"`;
|
||||
|
||||
@@ -1094,3 +1094,85 @@ describe("connected components and default values", () => {
|
||||
expect(fixture.innerHTML).toBe("<div>1</div>");
|
||||
});
|
||||
});
|
||||
|
||||
describe("various scenarios", () => {
|
||||
let fixture: HTMLElement;
|
||||
let env: Env;
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = makeTestFixture();
|
||||
env = makeTestEnv();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
fixture.remove();
|
||||
});
|
||||
|
||||
test("scenarios with async store updates and some components events", async () => {
|
||||
const actions = {
|
||||
async deleteAttachment({ state }) {
|
||||
await Promise.resolve();
|
||||
delete state.attachments[100];
|
||||
state.messages[10].attachmentIds = [];
|
||||
}
|
||||
};
|
||||
const state = {
|
||||
attachments: {
|
||||
100: {
|
||||
id: 100,
|
||||
name: "text.txt"
|
||||
}
|
||||
},
|
||||
messages: {
|
||||
10: {
|
||||
attachmentIds: [100],
|
||||
id: 10
|
||||
}
|
||||
}
|
||||
};
|
||||
const store = new Store({ actions, state });
|
||||
|
||||
env.qweb.addTemplates(`
|
||||
<templates>
|
||||
<div t-name="Message">
|
||||
<button t-on-click="doStuff">Do stuff</button>
|
||||
<Attachment t-foreach="storeProps.attachmentIds" t-key="attachmentId" t-as="attachmentId" id="attachmentId"/>
|
||||
</div>
|
||||
<div t-name="Attachment">
|
||||
<span>Attachment <t t-esc="props.id"/></span>
|
||||
<span>Name: <t t-esc="storeProps.name"/></span>
|
||||
</div>
|
||||
</templates>
|
||||
`);
|
||||
class Attachment extends ConnectedComponent<any, any, any> {
|
||||
static mapStoreToProps(state, ownProps) {
|
||||
return {
|
||||
name: state.attachments[ownProps.id].name
|
||||
};
|
||||
}
|
||||
}
|
||||
class Message extends ConnectedComponent<any, any, any> {
|
||||
static mapStoreToProps(state) {
|
||||
return {
|
||||
attachmentIds: state.messages[10].attachmentIds
|
||||
};
|
||||
}
|
||||
components = { Attachment };
|
||||
state = { isAttachmentDeleted: false };
|
||||
doStuff() {
|
||||
this.dispatch("deleteAttachment", 100);
|
||||
this.state.isAttachmentDeleted = true;
|
||||
}
|
||||
}
|
||||
|
||||
(<any>env).store = store;
|
||||
const message = new Message(env);
|
||||
await message.mount(fixture);
|
||||
|
||||
expect(fixture.innerHTML).toMatchSnapshot();
|
||||
|
||||
fixture.querySelector("button")!.click();
|
||||
await nextTick();
|
||||
expect(fixture.innerHTML).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user