React-apollo: Subscription Component: "Can't perform a React state update on an unmounted component." when onSubscriptionData triggers a parent's setState and unmounts the Subscription

Created on 21 Dec 2018  ·  12Comments  ·  Source: apollographql/react-apollo

Intended outcome:
I have a modal that contains two components, an input field and the Subscription component, which is listening to a single entry in the database for input from another device. Upon receiving an update, the component modal will unmount both components to display a spinner, blocking further inputs. This is done by passing down a binded function containing the modal's setState to the Subscription's onSubscriptionData. The rough structure follows this pseudocode:

// Rough structure, not functional
class MyModal extends React.Component {
    state = { loading: false }

    setToLoading = () => this.setState({ loading: true })

    render() {
        const { loading } = this.state;
        if (loading) {
            return (<Modal><Spinner /></Modal>);
        }
        return (
            <Modal>
                <InputField />
                <Subscription onSubscriptionData={this.setToLoading} />
            </Modal>
        );
    }
}

The intended outcome is that there's no error output in the browser console indicating a "memory leak".

Actual outcome:
The UI renders properly (i.e. setToLoading runs, and the modal switches to the spinner. However, the browser console will display the following error.
image

How to reproduce the issue:
I'm not sure this small issue warrants a full sandbox reproduction. In any case, I believe I may have found the cause. After some debugging, I reached this section of code in react-apollo:

// Inside src/Subscriptions.tsx
  private updateCurrentData = (result: SubscriptionResult<TData>) => {
    const {
      client,
      props: { onSubscriptionData },
    } = this;
    if (onSubscriptionData) onSubscriptionData({ client, subscriptionData: result });
    this.setState({
      data: result.data,
      loading: false,
      error: undefined,
    });
  };

In this code, onSubscriptionData is run before this.setState. This means the parent component's setState gets run before the Subscription's. When I switched the order, my error went away.

Version

Most helpful comment

Hi everyone! A fix for this issue has been merged with the codebase. It will be included in the next release of react-apollo.

All 12 comments

I believe I've run into the same issue, except using Query and subscribeToMore().

The same here...

Same story

Same here

This is really ruining my evening as well lol

Me too

any update on this?

Could I unsubscribe from Subscription in componentWillUnmount as React warning suggests?

@sorokinvj

There is no possibility to unsubscribe in componentWillUnmount without changing apollo source code

@sorokinvj

There is no possibility to unsubscribe in componentWillUnmount without changing apollo source code

ok, so I guess I should take another approach with subscribeToMore

Hi everyone! A fix for this issue has been merged with the codebase. It will be included in the next release of react-apollo.

Has this updated version already been released, @jasonpaulos? Thank you.

@darrylyoung yes, I believe this fix was included in react-apollo 2.5.7.

Was this page helpful?
0 / 5 - 0 ratings