Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save bvaughn/982ab689a41097237f6e9860db7ca8d6 to your computer and use it in GitHub Desktop.

Select an option

Save bvaughn/982ab689a41097237f6e9860db7ca8d6 to your computer and use it in GitHub Desktop.
Example for loading new external data in response to updated props
// This is an example of how to fetch external data in response to updated props,
// If you are using an async mechanism that does not support cancellation (e.g. a Promise).
class ExampleComponent extends React.Component {
_currentId = null;
state = {
externalData: null
};
static getDerivedStateFromProps(nextProps, prevState) {
// Store prevId in state so we can compare when props change.
// Clear out previously-loaded data (so we don't render stale stuff).
if (nextProps.id !== prevState.prevId) {
return {
externalData: null,
prevId: nextProps.id
};
}
// No state update necessary
return null;
}
componentDidMount() {
this._loadAsyncData(this.props.id);
}
componentDidUpdate(prevProps, prevState) {
if (this.state.externalData === null) {
this._loadAsyncData(this.props.id);
}
}
componentWillUnmount() {
// Prevent potential setState calls after unmount,
// (Since these trigger DEV warnigs)
_currentId = null;
}
render() {
if (this.state.externalData === null) {
// Render loading state ...
} else {
// Render real UI ...
}
}
_loadAsyncData(id) {
if (id === this._currentId) {
// Data for this id is already loading
}
this._currentId = id;
asyncLoadData(id).then(externalData => {
// Only update state if the Promise that has just resolved,
// Reflects the most recently requested external data.
if (id === this._currentId) {
this.setState({ externalData });
}
});
}
}
@tranvansang
Copy link
Copy Markdown

shouldn't asyncLoadData catch error?

    asyncLoadData(id).then(externalData => {
      // Only update state if the Promise that has just resolved,
      // Reflects the most recently requested external data.
      if (id === this._currentId) {
        this.setState({ externalData });
      }
    });

should be

    asyncLoadData(id).then(externalData => {
      // Only update state if the Promise that has just resolved,
      // Reflects the most recently requested external data.
      if (id === this._currentId) {
        this.setState({ externalData });
      }
    }).catch(() => this._currentId = null);

@kasajian
Copy link
Copy Markdown

kasajian commented Mar 9, 2019

akonsu's change is required.
inomdzhon's change is required.

If the author isn't going to update the gist, could someone else create a new one, along with a online running example?

@aidanlister
Copy link
Copy Markdown

@Stephen-ONeil I feel the same way, if (id === this._currentId) { is basically just an isMounted check ...

@tmkasun
Copy link
Copy Markdown

tmkasun commented Aug 9, 2019

A bug:

componentDidUpdate(prevProps, prevState) {
    if (prevState.externalData === null) {
      this._loadAsyncData(this.props.id);
    }
  }

must read

componentDidUpdate(prevProps, prevState) {
    if (this.state.externalData === null) {
      this._loadAsyncData(this.props.id);
    }
  }

Yes, This will cause the second render to fail. Because prevState is having old data now.

Blog post have the correct code

@bvaughn
Copy link
Copy Markdown
Author

bvaughn commented Aug 9, 2019

Thanks for pointing out the typo. I often don't notice comments on Gists. I've updated the example.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment