diff --git a/content/blog/2018-02-07-update-on-async-rendering.md b/content/blog/2018-02-07-update-on-async-rendering.md index 6f2fea67..96845367 100644 --- a/content/blog/2018-02-07-update-on-async-rendering.md +++ b/content/blog/2018-02-07-update-on-async-rendering.md @@ -75,12 +75,12 @@ The simplest refactor for this type of component is to move state initialization ### Fetching external data -Here is an example of a component that uses `componentWillMount` to fetch external data:: +Here is an example of a component that uses `componentWillMount` and `componentWillUpdate` to fetch external data:: `embed:update-on-async-rendering/fetching-external-data-before.js` The above code is problematic for both server rendering (where the external data won't be used) and the upcoming async rendering mode (where the request might be initiated multiple times). -The recommended upgrade path for most use cases is to move data-fetching into `componentDidMount`: +The recommended upgrade path for most use cases is to move data-fetching into `componentDidMount` and `componentDidUpdate`: `embed:update-on-async-rendering/fetching-external-data-after.js` There is a common misconception that fetching in `componentWillMount` lets you avoid the first empty rendering state. In practice this was never true because React has always executed `render` immediately after `componentWillMount`. If the data is not available by the time `componentWillMount` fires, the first `render` will still show a loading state regardless of where you initiate the fetch. This is why moving the fetch to `componentDidMount` has no perceptible effect in the vast majority of cases. diff --git a/examples/update-on-async-rendering/fetching-external-data-after.js b/examples/update-on-async-rendering/fetching-external-data-after.js index 4460c215..4aae7722 100644 --- a/examples/update-on-async-rendering/fetching-external-data-after.js +++ b/examples/update-on-async-rendering/fetching-external-data-after.js @@ -7,7 +7,7 @@ class ExampleComponent extends React.Component { // highlight-range{1-9} componentDidMount() { this._currentRequest = asyncLoadData( - this.props.someID, + this.props.id, externalData => { this._currentRequest = null; this.setState({externalData}); @@ -15,6 +15,19 @@ class ExampleComponent extends React.Component { ); } // highlight-line + // highlight-range{1-11} + componentDidUpdate(prevProps, prevState) { + if (prevProps.id !== this.props.id) { + this._currentRequest = asyncLoadData( + this.props.id, + externalData => { + this._currentRequest = null; + this.setState({externalData}); + } + ); + } + } + // highlight-line // highlight-range{1-5} componentWillUnmount() { if (this._currentRequest) { diff --git a/examples/update-on-async-rendering/fetching-external-data-before.js b/examples/update-on-async-rendering/fetching-external-data-before.js index c7d4e025..ebe7c4b8 100644 --- a/examples/update-on-async-rendering/fetching-external-data-before.js +++ b/examples/update-on-async-rendering/fetching-external-data-before.js @@ -6,10 +6,19 @@ class ExampleComponent extends React.Component { // highlight-range{1-5} componentWillMount() { - asyncLoadData(this.props.someId).then(externalData => + asyncLoadData(this.props.id).then(externalData => this.setState({externalData}) ); } + // highlight-line + // highlight-range{1-7} + componentWillReceiveProps(nextProps) { + if (nextProps.id !== this.props.id) { + asyncLoadData(this.props.id).then(externalData => + this.setState({externalData}) + ); + } + } render() { if (this.externalData === null) {