mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
@@ -12,19 +12,20 @@ export class ConnectedComponent<T extends Env, P, S> extends Component<T, P, S>
|
||||
return env.store;
|
||||
}
|
||||
|
||||
hashFunction: HashFunction = ({ storeProps }, options) => {
|
||||
const observer = (this.__owl__ as any).store.observer;
|
||||
let refFunction = this.deep ? observer.deepRevNumber : observer.revNumber;
|
||||
if ("__owl__" in storeProps) {
|
||||
return refFunction.call(observer, storeProps);
|
||||
storeProps: any;
|
||||
|
||||
hashFunction: HashFunction = (storeProps, options) => {
|
||||
const revFn = (this.__owl__ as any).revFn;
|
||||
const rev = revFn(storeProps);
|
||||
if (rev > 0) {
|
||||
return rev;
|
||||
}
|
||||
const { currentStoreProps } = options;
|
||||
let hash = 0;
|
||||
for (let key in storeProps) {
|
||||
const val = storeProps[key];
|
||||
const hashVal = refFunction.call(observer, val);
|
||||
const hashVal = revFn(val);
|
||||
if (hashVal === 0) {
|
||||
if (val !== currentStoreProps[key]) {
|
||||
if (val !== options.prevStoreProps[key]) {
|
||||
options.didChange = true;
|
||||
}
|
||||
} else {
|
||||
@@ -37,32 +38,23 @@ export class ConnectedComponent<T extends Env, P, S> extends Component<T, P, S>
|
||||
static mapStoreToProps(storeState, ownProps, getters) {
|
||||
return {};
|
||||
}
|
||||
constructor(parent, props?: any) {
|
||||
super(parent, props);
|
||||
|
||||
/**
|
||||
* Need to do this here so 'deep' can be overrided by subcomponent easily
|
||||
*/
|
||||
async __prepareAndRender(scope?: Object, vars?: any): ReturnType<Component<any,any,any>["__prepareAndRender"]> {
|
||||
const store = this.getStore(this.env);
|
||||
const ownProps = this.props || {};
|
||||
const storeProps = (<any>this.constructor).mapStoreToProps(
|
||||
store.state,
|
||||
ownProps,
|
||||
store.getters
|
||||
);
|
||||
const mergedProps = Object.assign({}, ownProps, storeProps);
|
||||
|
||||
this.props = mergedProps;
|
||||
|
||||
(<any>this.__owl__).ownProps = ownProps;
|
||||
(<any>this.__owl__).currentStoreProps = storeProps;
|
||||
(<any>this.__owl__).store = store;
|
||||
(<any>this.__owl__).storeHash = this.hashFunction(
|
||||
{
|
||||
state: store.state,
|
||||
storeProps: storeProps
|
||||
},
|
||||
{
|
||||
currentStoreProps: storeProps
|
||||
}
|
||||
);
|
||||
this.storeProps = (<any>this.constructor).mapStoreToProps(store.state, ownProps, store.getters);
|
||||
const observer = store.observer;
|
||||
const revFn = this.deep ? observer.deepRevNumber : observer.revNumber;
|
||||
(this.__owl__ as any).store = store;
|
||||
(this.__owl__ as any).revFn = revFn.bind(observer);
|
||||
(this.__owl__ as any).storeHash = this.hashFunction(this.storeProps, {
|
||||
prevStoreProps: this.storeProps
|
||||
});
|
||||
(this.__owl__ as any).rev = observer.rev;
|
||||
return super.__prepareAndRender(scope, vars);
|
||||
}
|
||||
/**
|
||||
* We do not use the mounted hook here for a subtle reason: we want the
|
||||
@@ -70,56 +62,47 @@ export class ConnectedComponent<T extends Env, P, S> extends Component<T, P, S>
|
||||
* if we use the mounted hook, this will be done in the reverse order.
|
||||
*/
|
||||
__callMounted() {
|
||||
(<any>this.__owl__).store.on("update", this, this.__checkUpdate);
|
||||
(this.__owl__ as any).store.on("update", this, this.__checkUpdate);
|
||||
super.__callMounted();
|
||||
}
|
||||
willUnmount() {
|
||||
(<any>this.__owl__).store.off("update", this);
|
||||
super.willUnmount();
|
||||
__callWillUnmount() {
|
||||
(this.__owl__ as any).store.off("update", this);
|
||||
super.__callWillUnmount();
|
||||
}
|
||||
|
||||
async __checkUpdate(updateId) {
|
||||
if (updateId === (<any>this.__owl__).currentUpdateId) {
|
||||
return;
|
||||
}
|
||||
const ownProps = (<any>this.__owl__).ownProps;
|
||||
const storeProps = (<any>this.constructor).mapStoreToProps(
|
||||
(<any>this.__owl__).store.state,
|
||||
ownProps,
|
||||
(<any>this.__owl__).store.getters
|
||||
);
|
||||
const options: any = {
|
||||
currentStoreProps: (<any>this.__owl__).currentStoreProps
|
||||
};
|
||||
const storeHash = this.hashFunction(
|
||||
{
|
||||
state: (<any>this.__owl__).store.state,
|
||||
storeProps: storeProps
|
||||
},
|
||||
options
|
||||
);
|
||||
let didChange = options.didChange;
|
||||
if (storeHash !== (<any>this.__owl__).storeHash) {
|
||||
didChange = true;
|
||||
(<any>this.__owl__).storeHash = storeHash;
|
||||
}
|
||||
if (didChange) {
|
||||
(<any>this.__owl__).currentStoreProps = storeProps;
|
||||
await this.__updateProps(ownProps, false);
|
||||
}
|
||||
async __updateProps(nextProps: P, f, p, s, v) {
|
||||
this.__updateStoreProps(nextProps);
|
||||
return super.__updateProps(nextProps, f, p, s, v);
|
||||
}
|
||||
__updateProps(nextProps, forceUpdate, patchQueue?: any[]) {
|
||||
const __owl__ = <any>this.__owl__;
|
||||
__owl__.currentUpdateId = __owl__.store._updateId;
|
||||
if (__owl__.ownProps !== nextProps) {
|
||||
__owl__.currentStoreProps = (<any>this.constructor).mapStoreToProps(
|
||||
__owl__.store.state,
|
||||
nextProps,
|
||||
__owl__.store.getters
|
||||
);
|
||||
|
||||
__updateStoreProps(nextProps): boolean {
|
||||
const store = (this.__owl__ as any).store;
|
||||
const storeProps = (<any>this.constructor).mapStoreToProps(
|
||||
store.state,
|
||||
nextProps,
|
||||
store.getters
|
||||
);
|
||||
const options = { prevStoreProps: this.storeProps, didChange: false };
|
||||
const storeHash = this.hashFunction(storeProps, options);
|
||||
this.storeProps = storeProps;
|
||||
let didChange = options.didChange;
|
||||
if (storeHash !== (this.__owl__ as any).storeHash) {
|
||||
(this.__owl__ as any).storeHash = storeHash;
|
||||
didChange = true;
|
||||
}
|
||||
(this.__owl__ as any).rev = store.observer.rev;
|
||||
return didChange
|
||||
}
|
||||
|
||||
async __checkUpdate() {
|
||||
const observer = (this.__owl__ as any).store.observer;
|
||||
if (observer.rev === (this.__owl__ as any).rev) {
|
||||
// update was already done by updateProps, from parent
|
||||
return;
|
||||
}
|
||||
const didChange = this.__updateStoreProps(this.props);
|
||||
if (didChange) {
|
||||
this.render();
|
||||
}
|
||||
__owl__.ownProps = nextProps;
|
||||
const mergedProps = Object.assign({}, nextProps, __owl__.currentStoreProps);
|
||||
return super.__updateProps(mergedProps, forceUpdate, patchQueue);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ describe("connecting a component to store", () => {
|
||||
env.qweb.addTemplates(`
|
||||
<templates>
|
||||
<div t-name="App">
|
||||
<t t-foreach="props.todos" t-as="todo" >
|
||||
<t t-foreach="storeProps.todos" t-as="todo" >
|
||||
<Todo msg="todo.msg" t-key="todo"/>
|
||||
</t>
|
||||
</div>
|
||||
@@ -56,7 +56,7 @@ describe("connecting a component to store", () => {
|
||||
env.qweb.addTemplates(`
|
||||
<templates>
|
||||
<div t-name="App">
|
||||
<span t-foreach="props.todos" t-as="todo" t-key="todo">
|
||||
<span t-foreach="storeProps.todos" t-as="todo" t-key="todo">
|
||||
<t t-esc="todo.title"/>
|
||||
</span>
|
||||
</div>
|
||||
@@ -104,7 +104,7 @@ describe("connecting a component to store", () => {
|
||||
env.qweb.addTemplates(`
|
||||
<templates>
|
||||
<div t-name="App">
|
||||
<t t-foreach="props.todos" t-as="todo">
|
||||
<t t-foreach="storeProps.todos" t-as="todo">
|
||||
<Todo msg="todo.msg" t-key="todo" />
|
||||
</t>
|
||||
</div>
|
||||
@@ -196,9 +196,9 @@ describe("connecting a component to store", () => {
|
||||
|
||||
env.qweb.addTemplates(`
|
||||
<templates>
|
||||
<span t-name="TodoItem"><t t-esc="props.text"/></span>
|
||||
<span t-name="TodoItem"><t t-esc="storeProps.text"/></span>
|
||||
<div t-name="TodoList">
|
||||
<t t-foreach="props.todos" t-as="todo">
|
||||
<t t-foreach="storeProps.todos" t-as="todo">
|
||||
<TodoItem id="todo.id" t-key="todo.id"/>
|
||||
</t>
|
||||
</div>
|
||||
@@ -247,11 +247,11 @@ describe("connecting a component to store", () => {
|
||||
env.qweb.addTemplates(`
|
||||
<templates>
|
||||
<div t-name="TodoItem">
|
||||
<span><t t-esc="props.activeTodoText"/></span>
|
||||
<span><t t-esc="props.importantTodoText"/></span>
|
||||
<span><t t-esc="storeProps.activeTodoText"/></span>
|
||||
<span><t t-esc="storeProps.importantTodoText"/></span>
|
||||
</div>
|
||||
<div t-name="TodoList">
|
||||
<t t-foreach="props.todos" t-as="todo">
|
||||
<t t-foreach="storeProps.todos" t-as="todo">
|
||||
<TodoItem id="todo.id" t-key="todo.id"/>
|
||||
</t>
|
||||
</div>
|
||||
@@ -287,7 +287,7 @@ describe("connecting a component to store", () => {
|
||||
test("connected component is updated when props are updated", async () => {
|
||||
env.qweb.addTemplates(`
|
||||
<templates>
|
||||
<span t-name="Beer"><t t-esc="props.name"/></span>
|
||||
<span t-name="Beer"><t t-esc="storeProps.name"/></span>
|
||||
<div t-name="App">
|
||||
<Beer id="state.beerId"/>
|
||||
</div>
|
||||
@@ -322,7 +322,7 @@ describe("connecting a component to store", () => {
|
||||
env.qweb.addTemplates(`
|
||||
<templates>
|
||||
<div t-name="App">
|
||||
<span t-foreach="props.beers" t-as="beer" t-key="beer.name"><t t-esc="beer.name"/></span>
|
||||
<span t-foreach="storeProps.beers" t-as="beer" t-key="beer.name"><t t-esc="beer.name"/></span>
|
||||
</div>
|
||||
</templates>
|
||||
`);
|
||||
@@ -357,9 +357,9 @@ describe("connecting a component to store", () => {
|
||||
env.qweb.addTemplates(`
|
||||
<templates>
|
||||
<div t-name="Beer">
|
||||
<span>taster:<t t-esc="props.taster"/></span>
|
||||
<span t-if="props.selected">selected:<t t-esc="props.selected.name"/></span>
|
||||
<span t-if="props.consumed">consumed:<t t-esc="props.consumed.name"/></span>
|
||||
<span>taster:<t t-esc="storeProps.taster"/></span>
|
||||
<span t-if="storeProps.selected">selected:<t t-esc="storeProps.selected.name"/></span>
|
||||
<span t-if="storeProps.consumed">consumed:<t t-esc="storeProps.consumed.name"/></span>
|
||||
</div>
|
||||
<div t-name="App">
|
||||
<Beer id="state.beerId"/>
|
||||
@@ -424,9 +424,9 @@ describe("connecting a component to store", () => {
|
||||
env.qweb.addTemplates(`
|
||||
<templates>
|
||||
<div t-name="Beer">
|
||||
<span>taster:<t t-esc="props.taster"/></span>
|
||||
<span t-if="props.selected">selected:<t t-esc="props.selected.name"/></span>
|
||||
<span t-if="props.consumed">consumed:<t t-esc="props.consumed.name"/></span>
|
||||
<span>taster:<t t-esc="storeProps.taster"/></span>
|
||||
<span t-if="storeProps.selected">selected:<t t-esc="storeProps.selected.name"/></span>
|
||||
<span t-if="storeProps.consumed">consumed:<t t-esc="storeProps.consumed.name"/></span>
|
||||
</div>
|
||||
<div t-name="App">
|
||||
<Beer id="state.beerId"/>
|
||||
@@ -517,9 +517,9 @@ describe("connecting a component to store", () => {
|
||||
env.qweb.addTemplates(`
|
||||
<templates>
|
||||
<div t-name="Parent">
|
||||
<Child key="props.current"/>
|
||||
<Child key="storeProps.current"/>
|
||||
</div>
|
||||
<span t-name="Child"><t t-esc="props.msg"/></span>
|
||||
<span t-name="Child"><t t-esc="storeProps.msg"/></span>
|
||||
</templates>
|
||||
`);
|
||||
|
||||
@@ -577,13 +577,13 @@ describe("connecting a component to store", () => {
|
||||
env.qweb.addTemplates(`
|
||||
<templates>
|
||||
<div t-name="TodoApp" class="todoapp">
|
||||
<t t-foreach="Object.values(props.todos)" t-as="todo">
|
||||
<t t-foreach="Object.values(storeProps.todos)" t-as="todo">
|
||||
<TodoItem t-key="todo.id" id="todo.id"/>
|
||||
</t>
|
||||
</div>
|
||||
|
||||
<div t-name="TodoItem" class="todo">
|
||||
<t t-esc="props.todo.title"/>
|
||||
<t t-esc="storeProps.todo.title"/>
|
||||
<button class="destroy" t-on-click="editTodo">x</button>
|
||||
</div>
|
||||
</templates>
|
||||
@@ -656,13 +656,13 @@ describe("connecting a component to store", () => {
|
||||
env.qweb.addTemplates(`
|
||||
<templates>
|
||||
<div t-name="TodoApp" class="todoapp">
|
||||
<t t-foreach="Object.values(props.todos)" t-as="todo">
|
||||
<t t-foreach="Object.values(storeProps.todos)" t-as="todo">
|
||||
<TodoItem t-key="todo.id" id="todo.id"/>
|
||||
</t>
|
||||
</div>
|
||||
|
||||
<div t-name="TodoItem" class="todo">
|
||||
<t t-esc="props.todo.title"/>
|
||||
<t t-esc="storeProps.todo.title"/>
|
||||
<button class="destroy" t-on-click="removeTodo">x</button>
|
||||
</div>
|
||||
</templates>
|
||||
@@ -720,7 +720,7 @@ describe("connecting a component to store", () => {
|
||||
|
||||
env.qweb.addTemplates(`
|
||||
<templates>
|
||||
<div t-name="App"><t t-esc="props.msg"/></div>
|
||||
<div t-name="App"><t t-esc="storeProps.msg"/></div>
|
||||
</templates>
|
||||
`);
|
||||
|
||||
@@ -829,11 +829,11 @@ describe("connected components and default values", () => {
|
||||
<templates>
|
||||
<div t-name="Message">
|
||||
<t t-if="props.showId"><t t-esc="props.messageId"/></t>
|
||||
<t t-esc="props.message.content"/>
|
||||
<t t-esc="storeProps.message.content"/>
|
||||
</div>
|
||||
<div t-name="Thread">
|
||||
<t t-if="props.showMessages">
|
||||
<Message t-foreach="props.thread.messages" t-as="messageId" messageId="messageId" t-key="messageId"/>
|
||||
<Message t-foreach="storeProps.thread.messages" t-as="messageId" messageId="messageId" t-key="messageId"/>
|
||||
</t>
|
||||
</div>
|
||||
<div t-name="App"><Thread threadId="props.threadId"/></div>
|
||||
|
||||
Reference in New Issue
Block a user