mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
[FIX] store: ensure useStore proper clean up on destroy
This commit is contained in:
committed by
Géry Debongnie
parent
6c753bb49f
commit
a6f9b26057
+12
-6
@@ -84,6 +84,7 @@ const isStrictEqual = (a, b) => a === b;
|
|||||||
|
|
||||||
export function useStore(selector, options: SelectorOptions = {}): any {
|
export function useStore(selector, options: SelectorOptions = {}): any {
|
||||||
const component: Component<any, any> = Component.current!;
|
const component: Component<any, any> = Component.current!;
|
||||||
|
const componentId = component.__owl__.id;
|
||||||
const store = options.store || (component.env.store as Store);
|
const store = options.store || (component.env.store as Store);
|
||||||
if (!(store instanceof Store)) {
|
if (!(store instanceof Store)) {
|
||||||
throw new Error(`No store found when connecting '${component.constructor.name}'`);
|
throw new Error(`No store found when connecting '${component.constructor.name}'`);
|
||||||
@@ -92,11 +93,10 @@ export function useStore(selector, options: SelectorOptions = {}): any {
|
|||||||
const hashFn = store.observer.revNumber.bind(store.observer);
|
const hashFn = store.observer.revNumber.bind(store.observer);
|
||||||
let revNumber = hashFn(result);
|
let revNumber = hashFn(result);
|
||||||
const isEqual = options.isEqual || isStrictEqual;
|
const isEqual = options.isEqual || isStrictEqual;
|
||||||
if (!store.updateFunctions[component.__owl__.id]) {
|
if (!store.updateFunctions[componentId]) {
|
||||||
store.updateFunctions[component.__owl__.id] = [];
|
store.updateFunctions[componentId] = [];
|
||||||
}
|
}
|
||||||
const updateFunctions = store.updateFunctions[component.__owl__.id];
|
store.updateFunctions[componentId].push(function(): boolean {
|
||||||
updateFunctions.push(function(): boolean {
|
|
||||||
const oldResult = result;
|
const oldResult = result;
|
||||||
result = selector(store!.state, component.props);
|
result = selector(store!.state, component.props);
|
||||||
const newRevNumber = hashFn(result);
|
const newRevNumber = hashFn(result);
|
||||||
@@ -115,7 +115,7 @@ export function useStore(selector, options: SelectorOptions = {}): any {
|
|||||||
|
|
||||||
useContextWithCB(store, component, function(): Promise<void> | void {
|
useContextWithCB(store, component, function(): Promise<void> | void {
|
||||||
let shouldRender = false;
|
let shouldRender = false;
|
||||||
for (let fn of updateFunctions) {
|
for (let fn of store.updateFunctions[componentId]) {
|
||||||
shouldRender = fn() || shouldRender;
|
shouldRender = fn() || shouldRender;
|
||||||
}
|
}
|
||||||
if (shouldRender) {
|
if (shouldRender) {
|
||||||
@@ -123,9 +123,15 @@ export function useStore(selector, options: SelectorOptions = {}): any {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
onWillUpdateProps(props => {
|
onWillUpdateProps(props => {
|
||||||
delete store.updateFunctions[component.__owl__.id];
|
|
||||||
result = selector(store.state, props);
|
result = selector(store.state, props);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const __destroy = component.__destroy;
|
||||||
|
component.__destroy = parent => {
|
||||||
|
delete store.updateFunctions[componentId];
|
||||||
|
__destroy.call(component, parent);
|
||||||
|
};
|
||||||
|
|
||||||
if (typeof result !== "object") {
|
if (typeof result !== "object") {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -490,6 +490,25 @@ describe("connecting a component to store", () => {
|
|||||||
expect(fixture.innerHTML).toBe("<div><span>jupiler</span><span>kwak</span></div>");
|
expect(fixture.innerHTML).toBe("<div><span>jupiler</span><span>kwak</span></div>");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("connected component is properly cleaned up on destroy", async () => {
|
||||||
|
class App extends Component<any, any> {
|
||||||
|
static template = xml`<div></div>`;
|
||||||
|
state = useStore((state, props) => state);
|
||||||
|
}
|
||||||
|
|
||||||
|
const store = new Store({ state: {} });
|
||||||
|
(<any>env).store = store;
|
||||||
|
const app = new App();
|
||||||
|
|
||||||
|
await app.mount(fixture);
|
||||||
|
expect(fixture.innerHTML).toBe("<div></div>");
|
||||||
|
expect(store.updateFunctions[app.__owl__.id].length).toBe(1);
|
||||||
|
|
||||||
|
app.destroy();
|
||||||
|
|
||||||
|
expect(store.updateFunctions[app.__owl__.id]).toBe(undefined);
|
||||||
|
});
|
||||||
|
|
||||||
test("connected component with undefined, null and string props", async () => {
|
test("connected component with undefined, null and string props", async () => {
|
||||||
class Beer extends Component<any, any> {
|
class Beer extends Component<any, any> {
|
||||||
static template = xml`
|
static template = xml`
|
||||||
|
|||||||
Reference in New Issue
Block a user