Skip to content
This repository was archived by the owner on Aug 23, 2022. It is now read-only.

Commit e3c237e

Browse files
authored
Merge pull request #815 from kabbi/fix-resolve-dynamic-model
Fixed deeply dynamic model support
2 parents 23c20e4 + f002ef2 commit e3c237e

File tree

3 files changed

+48
-16
lines changed

3 files changed

+48
-16
lines changed

src/components/control-component.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -676,8 +676,8 @@ function createControlClass(s = defaultStrategy) {
676676
/* eslint-disable react/prop-types */
677677
/* eslint-disable react/no-multi-comp */
678678
class DefaultConnectedControl extends React.Component {
679-
shouldComponentUpdate(nextProps) {
680-
return !shallowEqual(this.props, nextProps, {
679+
shouldComponentUpdate(nextProps, nextState, nextContext) {
680+
return !shallowEqual(this.context, nextContext) || !shallowEqual(this.props, nextProps, {
681681
deepKeys: ['controlProps'],
682682
omitKeys: ['mapProps'],
683683
});
@@ -696,6 +696,9 @@ function createControlClass(s = defaultStrategy) {
696696
}
697697
}
698698

699+
// Copy the context types so that we can properly implement shouldComponentUpdate
700+
DefaultConnectedControl.contextTypes = ConnectedControl.contextTypes;
701+
699702
DefaultConnectedControl.custom = ConnectedControl;
700703

701704
class DefaultConnectedControlInput extends DefaultConnectedControl {

src/utils/resolve-model.js

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,29 +20,22 @@ function resolveModel(model, parentModel) {
2020

2121
export default function wrapWithModelResolver(WrappedComponent, deepKeys = [], omitKeys = []) {
2222
class ResolvedModelWrapper extends ReactComponent {
23-
constructor(props, context) {
24-
super(props, context);
25-
26-
this.model = context.model;
27-
this.store = context.localStore;
28-
this.deepKeys = deepKeys;
29-
this.omitKeys = omitKeys;
30-
}
31-
shouldComponentUpdate(nextProps) {
32-
return !shallowEqual(this.props, nextProps, {
33-
deepKeys: this.deepKeys,
34-
omitKeys: this.omitKeys,
23+
shouldComponentUpdate(nextProps, nextState, nextContext) {
24+
return !shallowEqual(this.context, nextContext) || !shallowEqual(this.props, nextProps, {
25+
deepKeys,
26+
omitKeys,
3527
});
3628
}
3729
render() {
30+
const { model: parentModel, localStore } = this.context;
3831
const resolvedModel = resolveModel(
3932
this.props.model,
40-
this.model);
33+
parentModel);
4134

4235
return (<WrappedComponent
4336
{...this.props}
4437
model={resolvedModel}
45-
store={this.store || undefined}
38+
store={localStore || undefined}
4639
/>);
4740
}
4841
}

test/model-resolving-spec.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,4 +195,40 @@ describe('model resolving', () => {
195195
assert.equal(controlInput.value, 'control value');
196196
});
197197
});
198+
199+
it('deep resolves with dynamic model', () => {
200+
const deepInitialState = {
201+
foo: { value: 'fooValue' },
202+
bar: { value: 'barValue' },
203+
};
204+
205+
const deepStore = testCreateStore({
206+
test: modelReducer('test', deepInitialState),
207+
testForm: formReducer('test', deepInitialState),
208+
});
209+
210+
class DynamicSubform extends React.Component {
211+
state = { model: '.foo' };
212+
render() {
213+
return (
214+
<Fieldset model={this.state.model}>
215+
<button onClick={() => this.setState({ model: '.bar' })} />
216+
<Control.text model=".value" />
217+
</Fieldset>
218+
);
219+
}
220+
}
221+
222+
const app = testRender(
223+
<Form model="test">
224+
<DynamicSubform />
225+
</Form>, deepStore);
226+
227+
const input = TestUtils.findRenderedDOMComponentWithTag(app, 'input');
228+
const button = TestUtils.findRenderedDOMComponentWithTag(app, 'button');
229+
230+
assert.equal(input.value, 'fooValue');
231+
TestUtils.Simulate.click(button);
232+
assert.equal(input.value, 'barValue');
233+
});
198234
});

0 commit comments

Comments
 (0)