Skip to content

Commit a440b6e

Browse files
committed
Merge pull request #96 from rackt/dont-setstate-when-unmounted
Don't set state if unmounted during dispatch
2 parents 98021f0 + 786189c commit a440b6e

File tree

3 files changed

+45
-5
lines changed

3 files changed

+45
-5
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
"mocha-jsdom": "~0.4.0",
5353
"react": "^0.14.0-beta3",
5454
"react-addons-test-utils": "^0.14.0-beta3",
55+
"react-dom": "^0.14.0-beta3",
5556
"redux": "^2.0.0",
5657
"rimraf": "^2.3.4",
5758
"webpack": "^1.11.0"

src/components/createConnect.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,10 @@ export default function createConnect(React) {
189189
}
190190

191191
handleChange() {
192+
if (!this.unsubscribe) {
193+
return;
194+
}
195+
192196
if (this.updateStateProps()) {
193197
this.updateState();
194198
}

test/components/connect.spec.js

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import expect from 'expect';
22
import jsdom from 'mocha-jsdom';
33
import React, { createClass, Children, PropTypes, Component } from 'react';
4+
import ReactDOM from 'react-dom';
45
import TestUtils from 'react-addons-test-utils';
56
import { createStore } from 'redux';
67
import { connect } from '../../src/index';
@@ -643,7 +644,7 @@ describe('React', () => {
643644
};
644645

645646
@connect(
646-
state => ({string: state}),
647+
state => ({ string: state }),
647648
dispatch => ({ dispatch })
648649
)
649650
class Container extends Component {
@@ -652,18 +653,52 @@ describe('React', () => {
652653
}
653654
}
654655

655-
const tree = TestUtils.renderIntoDocument(
656+
const div = document.createElement('div');
657+
ReactDOM.render(
656658
<ProviderMock store={store}>
657659
<Container />
658-
</ProviderMock>
660+
</ProviderMock>,
661+
div
659662
);
660663

661-
const connector = TestUtils.findRenderedComponentWithType(tree, Container);
662664
expect(spy.calls.length).toBe(0);
663-
connector.componentWillUnmount();
665+
ReactDOM.unmountComponentAtNode(div);
664666
expect(spy.calls.length).toBe(1);
665667
});
666668

669+
it('should not attempt to set state after unmounting', () => {
670+
const store = createStore(stringBuilder);
671+
let mapStateToPropsCalls = 0;
672+
673+
@connect(
674+
() => ({ calls: ++mapStateToPropsCalls }),
675+
dispatch => ({ dispatch })
676+
)
677+
class Container extends Component {
678+
render() {
679+
return <Passthrough {...this.props} />;
680+
}
681+
}
682+
683+
const div = document.createElement('div');
684+
store.subscribe(() =>
685+
ReactDOM.unmountComponentAtNode(div)
686+
);
687+
ReactDOM.render(
688+
<ProviderMock store={store}>
689+
<Container />
690+
</ProviderMock>,
691+
div
692+
);
693+
694+
expect(mapStateToPropsCalls).toBe(2);
695+
const spy = expect.spyOn(console, 'error');
696+
store.dispatch({ type: 'APPEND', body: 'a'});
697+
spy.destroy();
698+
expect(spy.calls.length).toBe(0);
699+
expect(mapStateToPropsCalls).toBe(2);
700+
});
701+
667702
it('should shallowly compare the selected state to prevent unnecessary updates', () => {
668703
const store = createStore(stringBuilder);
669704
const spy = expect.createSpy(() => ({}));

0 commit comments

Comments
 (0)