imp: store connect: mapStateToProps receive ownProps

This commit is contained in:
Géry Debongnie
2019-04-02 13:39:34 +02:00
parent 7ebea5a486
commit a86d0b5b02
2 changed files with 63 additions and 23 deletions
+15 -14
View File
@@ -7,24 +7,20 @@ export function connect(mapStateToProps) {
return class extends Comp {
constructor(parent, props?: any) {
const env = parent instanceof Component ? parent.env : parent;
const storeProps = mapStateToProps(env.store.state);
props = Object.assign(props || {}, storeProps);
super(parent, props);
const ownProps = Object.assign({}, props || {});
const storeProps = mapStateToProps(env.store.state, ownProps);
const mergedProps = Object.assign(props || {}, storeProps);
super(parent, mergedProps);
this.__widget__.currentStoreProps = storeProps;
this.__widget__.ownProps = ownProps;
}
mounted() {
this.env.store.on("update", this, () => {
const storeProps = mapStateToProps(this.env.store.state);
const ownProps = this.__widget__.ownProps;
const storeProps = mapStateToProps(this.env.store.state, ownProps);
if (!shallowEqual(storeProps, this.__widget__.currentStoreProps)) {
this.__widget__.currentStoreProps = storeProps;
// probably not optimal, will do 2 object.assign, one here and
// one in updateProps.
const nextProps = Object.assign(
{},
this.props,
this.__widget__.currentStoreProps
);
this.updateProps(nextProps, false);
this.updateProps(ownProps, false);
}
});
super.mounted();
@@ -34,8 +30,13 @@ export function connect(mapStateToProps) {
super.willUnmount();
}
updateProps(nextProps, forceUpdate) {
nextProps = Object.assign(nextProps, this.__widget__.currentStoreProps);
return super.updateProps(nextProps, forceUpdate);
this.__widget__.ownProps = nextProps;
const mergedProps = Object.assign(
{},
nextProps,
this.__widget__.currentStoreProps
);
return super.updateProps(mergedProps, forceUpdate);
}
};
};
+48 -9
View File
@@ -112,13 +112,13 @@ describe("connecting a component to store", () => {
class Child extends Component<any, any, any> {
inlineTemplate = `<div/>`;
mounted() {
steps.push('child:mounted');
steps.push("child:mounted");
}
willUnmount() {
steps.push('child:willUnmount')
steps.push("child:willUnmount");
}
destroyed() {
steps.push('child:destroyed');
steps.push("child:destroyed");
}
}
@@ -142,16 +142,55 @@ describe("connecting a component to store", () => {
const parent = new Parent(env);
await parent.mount(fixture);
expect(steps).toEqual([
'child:mounted',
]);
expect(steps).toEqual(["child:mounted"]);
await parent.updateState({ child: false });
expect(steps).toEqual([
'child:mounted',
'child:willUnmount',
'child:destroyed',
"child:mounted",
"child:willUnmount",
"child:destroyed"
]);
});
test("connect receives ownprops as second argument", async () => {
const state = { todos: [{ id: 1, text: "jupiler" }] };
let nextId = 2;
const mutations = {
addTodo(state, text) {
state.todos.push({ text, id: nextId++ });
}
};
const store = new Store({ state, mutations });
class TodoItem extends Component<any, any, any> {
inlineTemplate = `<span><t t-esc="props.text"/></span>`;
}
const ConnectedTodo = connect((state, props) => {
const todo = state.todos.find(t => t.id === props.id);
return todo;
})(TodoItem);
class TodoList extends Component<any, any, any> {
inlineTemplate = `<div>
<t t-foreach="props.todos" t-as="todo">
<t t-widget="ConnectedTodo" t-props="todo"/>
</t>
</div>`;
widgets = { ConnectedTodo };
}
const ConnectedTodoList = connect(state => state)(TodoList);
(<any>env).store = store;
const app = new ConnectedTodoList(env);
await app.mount(fixture);
expect(fixture.innerHTML).toBe("<div><span>jupiler</span></div>");
store.commit("addTodo", "hoegaarden");
await nextTick();
expect(fixture.innerHTML).toBe(
"<div><span>jupiler</span><span>hoegaarden</span></div>"
);
});
});