Skip to content

Commit

Permalink
Don't set state if unmounted during dispatch
Browse files Browse the repository at this point in the history
Fixes #92, #95
  • Loading branch information
gaearon committed Sep 6, 2015
1 parent 98021f0 commit 8ac6dd4
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 5 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
"mocha-jsdom": "~0.4.0",
"react": "^0.14.0-beta3",
"react-addons-test-utils": "^0.14.0-beta3",
"react-dom": "^0.14.0-beta3",
"redux": "^2.0.0",
"rimraf": "^2.3.4",
"webpack": "^1.11.0"
Expand Down
4 changes: 4 additions & 0 deletions src/components/createConnect.js
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,10 @@ export default function createConnect(React) {
}

updateState(props = this.props) {
if (!this.unsubscribe) {
return;
}

const nextState = this.computeNextState(props);
if (!shallowEqual(nextState, this.state.props)) {
this.setState({
Expand Down
42 changes: 37 additions & 5 deletions test/components/connect.spec.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import expect from 'expect';
import jsdom from 'mocha-jsdom';
import React, { createClass, Children, PropTypes, Component } from 'react';
import ReactDOM from 'react-dom';
import TestUtils from 'react-addons-test-utils';
import { createStore } from 'redux';
import { connect } from '../../src/index';
Expand Down Expand Up @@ -643,7 +644,7 @@ describe('React', () => {
};

@connect(
state => ({string: state}),
state => ({ string: state }),
dispatch => ({ dispatch })
)
class Container extends Component {
Expand All @@ -652,18 +653,49 @@ describe('React', () => {
}
}

const tree = TestUtils.renderIntoDocument(
const div = document.createElement('div');
ReactDOM.render(
<ProviderMock store={store}>
<Container />
</ProviderMock>
</ProviderMock>,
div
);

const connector = TestUtils.findRenderedComponentWithType(tree, Container);
expect(spy.calls.length).toBe(0);
connector.componentWillUnmount();
ReactDOM.unmountComponentAtNode(div);
expect(spy.calls.length).toBe(1);
});

it('should not attempt to set state after unmounting', () => {
const store = createStore(stringBuilder);

@connect(
state => ({ string: state }),
dispatch => ({ dispatch })
)
class Container extends Component {
render() {
return <Passthrough {...this.props} />;
}
}

const div = document.createElement('div');
store.subscribe(() =>
ReactDOM.unmountComponentAtNode(div)
);
ReactDOM.render(
<ProviderMock store={store}>
<Container />
</ProviderMock>,
div
);

const spy = expect.spyOn(console, 'error');
store.dispatch({ type: 'APPEND', body: 'a'});
spy.destroy();
expect(spy.calls.length).toBe(0);
});

it('should shallowly compare the selected state to prevent unnecessary updates', () => {
const store = createStore(stringBuilder);
const spy = expect.createSpy(() => ({}));
Expand Down

0 comments on commit 8ac6dd4

Please sign in to comment.