Fix all setState calls after unmounted errors. Decided to create our own flag rather then using a cancellablePromise since there was little to be gained from this alternative

This commit is contained in:
Fabio Berger 2018-01-30 20:12:32 +01:00
parent 144a507a2e
commit e219772b2a
7 changed files with 90 additions and 43 deletions

View File

@ -33,8 +33,10 @@ export class EthWethConversionDialog extends React.Component<
EthWethConversionDialogProps, EthWethConversionDialogProps,
EthWethConversionDialogState EthWethConversionDialogState
> { > {
private _isUnmounted: boolean;
constructor() { constructor() {
super(); super();
this._isUnmounted = false;
this.state = { this.state = {
shouldShowIncompleteErrs: false, shouldShowIncompleteErrs: false,
hasErrors: false, hasErrors: false,
@ -46,6 +48,9 @@ export class EthWethConversionDialog extends React.Component<
// tslint:disable-next-line:no-floating-promises // tslint:disable-next-line:no-floating-promises
this._fetchEthTokenBalanceAsync(); this._fetchEthTokenBalanceAsync();
} }
public componentWillUnmount() {
this._isUnmounted = true;
}
public render() { public render() {
const convertDialogActions = [ const convertDialogActions = [
<FlatButton key="cancel" label="Cancel" onTouchTap={this._onCancel.bind(this)} />, <FlatButton key="cancel" label="Cancel" onTouchTap={this._onCancel.bind(this)} />,
@ -181,9 +186,11 @@ export class EthWethConversionDialog extends React.Component<
this.props.userAddress, this.props.userAddress,
this.props.token.address, this.props.token.address,
); );
if (!this._isUnmounted) {
this.setState({ this.setState({
isEthTokenBalanceLoaded: true, isEthTokenBalanceLoaded: true,
ethTokenBalance: balance, ethTokenBalance: balance,
}); });
} }
} }
}

View File

@ -54,8 +54,10 @@ interface EthWrappersState {
} }
export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersState> { export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersState> {
private _isUnmounted: boolean;
constructor(props: EthWrappersProps) { constructor(props: EthWrappersProps) {
super(props); super(props);
this._isUnmounted = false;
const outdatedWETHAddresses = this._getOutdatedWETHAddresses(); const outdatedWETHAddresses = this._getOutdatedWETHAddresses();
const outdatedWETHAddressToIsStateLoaded: OutdatedWETHAddressToIsStateLoaded = {}; const outdatedWETHAddressToIsStateLoaded: OutdatedWETHAddressToIsStateLoaded = {};
const outdatedWETHStateByAddress: OutdatedWETHStateByAddress = {}; const outdatedWETHStateByAddress: OutdatedWETHStateByAddress = {};
@ -91,6 +93,9 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt
// tslint:disable-next-line:no-floating-promises // tslint:disable-next-line:no-floating-promises
this._fetchWETHStateAsync(); this._fetchWETHStateAsync();
} }
public componentWillUnmount() {
this._isUnmounted = true;
}
public render() { public render() {
const etherToken = this._getEthToken(); const etherToken = this._getEthToken();
const wethBalance = ZeroEx.toUnitAmount(this.state.ethTokenState.balance, constants.DECIMAL_PLACES_ETH); const wethBalance = ZeroEx.toUnitAmount(this.state.ethTokenState.balance, constants.DECIMAL_PLACES_ETH);
@ -394,6 +399,7 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt
}; };
outdatedWETHAddressToIsStateLoaded[address] = true; outdatedWETHAddressToIsStateLoaded[address] = true;
} }
if (!this._isUnmounted) {
this.setState({ this.setState({
outdatedWETHStateByAddress, outdatedWETHStateByAddress,
outdatedWETHAddressToIsStateLoaded, outdatedWETHAddressToIsStateLoaded,
@ -404,6 +410,7 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt
isWethStateLoaded: true, isWethStateLoaded: true,
}); });
} }
}
private _getOutdatedWETHAddresses(): string[] { private _getOutdatedWETHAddresses(): string[] {
const outdatedWETHAddresses = _.compact( const outdatedWETHAddresses = _.compact(
_.map(configs.OUTDATED_WRAPPED_ETHERS, outdatedWrappedEtherByNetwork => { _.map(configs.OUTDATED_WRAPPED_ETHERS, outdatedWrappedEtherByNetwork => {

View File

@ -59,8 +59,10 @@ interface FillOrderState {
export class FillOrder extends React.Component<FillOrderProps, FillOrderState> { export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
private _validator: SchemaValidator; private _validator: SchemaValidator;
private _isUnmounted: boolean;
constructor(props: FillOrderProps) { constructor(props: FillOrderProps) {
super(props); super(props);
this._isUnmounted = false;
this.state = { this.state = {
globalErrMsg: '', globalErrMsg: '',
didOrderValidationRun: false, didOrderValidationRun: false,
@ -90,6 +92,9 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
public componentDidMount() { public componentDidMount() {
window.scrollTo(0, 0); window.scrollTo(0, 0);
} }
public componentWillUnmount() {
this._isUnmounted = true;
}
public render() { public render() {
return ( return (
<div className="clearfix lg-px4 md-px4 sm-px2" style={{ minHeight: 600 }}> <div className="clearfix lg-px4 md-px4 sm-px2" style={{ minHeight: 600 }}>
@ -456,12 +461,14 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> {
if (!_.isEmpty(orderJSON)) { if (!_.isEmpty(orderJSON)) {
orderJSONErrMsg = 'Submitted order JSON is not valid JSON'; orderJSONErrMsg = 'Submitted order JSON is not valid JSON';
} }
if (!this._isUnmounted) {
this.setState({ this.setState({
didOrderValidationRun: true, didOrderValidationRun: true,
orderJSON, orderJSON,
orderJSONErrMsg, orderJSONErrMsg,
parsedOrder, parsedOrder,
}); });
}
return; return;
} }

View File

@ -30,8 +30,10 @@ interface TokenAmountInputState {
} }
export class TokenAmountInput extends React.Component<TokenAmountInputProps, TokenAmountInputState> { export class TokenAmountInput extends React.Component<TokenAmountInputProps, TokenAmountInputState> {
private _isUnmounted: boolean;
constructor(props: TokenAmountInputProps) { constructor(props: TokenAmountInputProps) {
super(props); super(props);
this._isUnmounted = false;
const defaultAmount = new BigNumber(0); const defaultAmount = new BigNumber(0);
this.state = { this.state = {
balance: defaultAmount, balance: defaultAmount,
@ -43,6 +45,9 @@ export class TokenAmountInput extends React.Component<TokenAmountInputProps, Tok
// tslint:disable-next-line:no-floating-promises // tslint:disable-next-line:no-floating-promises
this._fetchBalanceAndAllowanceAsync(this.props.token.address, this.props.userAddress); this._fetchBalanceAndAllowanceAsync(this.props.token.address, this.props.userAddress);
} }
public componentWillUnmount() {
this._isUnmounted = true;
}
public componentWillReceiveProps(nextProps: TokenAmountInputProps) { public componentWillReceiveProps(nextProps: TokenAmountInputProps) {
if ( if (
nextProps.userAddress !== this.props.userAddress || nextProps.userAddress !== this.props.userAddress ||
@ -107,6 +112,7 @@ export class TokenAmountInput extends React.Component<TokenAmountInputProps, Tok
userAddress, userAddress,
tokenAddress, tokenAddress,
); );
if (!this._isUnmounted) {
this.setState({ this.setState({
balance, balance,
allowance, allowance,
@ -114,3 +120,4 @@ export class TokenAmountInput extends React.Component<TokenAmountInputProps, Tok
}); });
} }
} }
}

View File

@ -91,8 +91,10 @@ interface TokenBalancesState {
} }
export class TokenBalances extends React.Component<TokenBalancesProps, TokenBalancesState> { export class TokenBalances extends React.Component<TokenBalancesProps, TokenBalancesState> {
private _isUnmounted: boolean;
public constructor(props: TokenBalancesProps) { public constructor(props: TokenBalancesProps) {
super(props); super(props);
this._isUnmounted = false;
const initialTrackedTokenStateByAddress = this._getInitialTrackedTokenStateByAddress(props.trackedTokens); const initialTrackedTokenStateByAddress = this._getInitialTrackedTokenStateByAddress(props.trackedTokens);
this.state = { this.state = {
errorType: undefined, errorType: undefined,
@ -109,6 +111,9 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala
const trackedTokenAddresses = _.keys(this.state.trackedTokenStateByAddress); const trackedTokenAddresses = _.keys(this.state.trackedTokenStateByAddress);
this._fetchBalancesAndAllowancesAsync(trackedTokenAddresses); this._fetchBalancesAndAllowancesAsync(trackedTokenAddresses);
} }
public componentWillUnmount() {
this._isUnmounted = true;
}
public componentWillReceiveProps(nextProps: TokenBalancesProps) { public componentWillReceiveProps(nextProps: TokenBalancesProps) {
if (nextProps.userEtherBalance !== this.props.userEtherBalance) { if (nextProps.userEtherBalance !== this.props.userEtherBalance) {
if (this.state.isBalanceSpinnerVisible) { if (this.state.isBalanceSpinnerVisible) {
@ -671,10 +676,12 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala
isLoaded: true, isLoaded: true,
}; };
} }
if (!this._isUnmounted) {
this.setState({ this.setState({
trackedTokenStateByAddress, trackedTokenStateByAddress,
}); });
} }
}
private _getInitialTrackedTokenStateByAddress(trackedTokens: Token[]) { private _getInitialTrackedTokenStateByAddress(trackedTokens: Token[]) {
const trackedTokenStateByAddress: TokenStateByAddress = {}; const trackedTokenStateByAddress: TokenStateByAddress = {};
_.each(trackedTokens, token => { _.each(trackedTokens, token => {

View File

@ -78,8 +78,10 @@ const styles: Styles = {
}; };
export class Documentation extends React.Component<DocumentationAllProps, DocumentationState> { export class Documentation extends React.Component<DocumentationAllProps, DocumentationState> {
private _isUnmounted: boolean;
constructor(props: DocumentationAllProps) { constructor(props: DocumentationAllProps) {
super(props); super(props);
this._isUnmounted = false;
this.state = { this.state = {
docAgnosticFormat: undefined, docAgnosticFormat: undefined,
}; };
@ -92,6 +94,9 @@ export class Documentation extends React.Component<DocumentationAllProps, Docume
// tslint:disable-next-line:no-floating-promises // tslint:disable-next-line:no-floating-promises
this._fetchJSONDocsFireAndForgetAsync(preferredVersionIfExists); this._fetchJSONDocsFireAndForgetAsync(preferredVersionIfExists);
} }
public componentWillUnmount() {
this._isUnmounted = true;
}
public render() { public render() {
const menuSubsectionsBySection = _.isUndefined(this.state.docAgnosticFormat) const menuSubsectionsBySection = _.isUndefined(this.state.docAgnosticFormat)
? {} ? {}
@ -367,6 +372,7 @@ export class Documentation extends React.Component<DocumentationAllProps, Docume
); );
const docAgnosticFormat = this.props.docsInfo.convertToDocAgnosticFormat(versionDocObj as DoxityDocObj); const docAgnosticFormat = this.props.docsInfo.convertToDocAgnosticFormat(versionDocObj as DoxityDocObj);
if (!this._isUnmounted) {
this.setState( this.setState(
{ {
docAgnosticFormat, docAgnosticFormat,
@ -377,3 +383,4 @@ export class Documentation extends React.Component<DocumentationAllProps, Docume
); );
} }
} }
}

View File

@ -45,8 +45,10 @@ const styles: Styles = {
export class Wiki extends React.Component<WikiProps, WikiState> { export class Wiki extends React.Component<WikiProps, WikiState> {
private _wikiBackoffTimeoutId: number; private _wikiBackoffTimeoutId: number;
private _isUnmounted: boolean;
constructor(props: WikiProps) { constructor(props: WikiProps) {
super(props); super(props);
this._isUnmounted = false;
this.state = { this.state = {
articlesBySection: undefined, articlesBySection: undefined,
}; };
@ -56,6 +58,7 @@ export class Wiki extends React.Component<WikiProps, WikiState> {
this._fetchArticlesBySectionAsync(); this._fetchArticlesBySectionAsync();
} }
public componentWillUnmount() { public componentWillUnmount() {
this._isUnmounted = true;
clearTimeout(this._wikiBackoffTimeoutId); clearTimeout(this._wikiBackoffTimeoutId);
} }
public render() { public render() {
@ -179,6 +182,7 @@ export class Wiki extends React.Component<WikiProps, WikiState> {
return; return;
} }
const articlesBySection = await response.json(); const articlesBySection = await response.json();
if (!this._isUnmounted) {
this.setState( this.setState(
{ {
articlesBySection, articlesBySection,
@ -188,6 +192,7 @@ export class Wiki extends React.Component<WikiProps, WikiState> {
}, },
); );
} }
}
private _getMenuSubsectionsBySection(articlesBySection: ArticlesBySection) { private _getMenuSubsectionsBySection(articlesBySection: ArticlesBySection) {
const sectionNames = _.keys(articlesBySection); const sectionNames = _.keys(articlesBySection);
const menuSubsectionsBySection: { [section: string]: string[] } = {}; const menuSubsectionsBySection: { [section: string]: string[] } = {};