From 7ac0712ed8d8bbf5306282af09de14fafb98a039 Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Fri, 23 Mar 2018 12:42:57 -0700 Subject: [PATCH] Updated 16.3 blog post to account for getSnapshotBeforeUpdate lifecycle --- content/blog/2018-03-20-react-v-16-3.md | 8 +++--- content/docs/reference-react-component.md | 8 ++++-- .../get-snapshot-before-update.js | 27 +++++++++++++++++++ 3 files changed, 38 insertions(+), 5 deletions(-) create mode 100644 examples/react-component-reference/get-snapshot-before-update.js diff --git a/content/blog/2018-03-20-react-v-16-3.md b/content/blog/2018-03-20-react-v-16-3.md index b2471bf8..272b40d2 100644 --- a/content/blog/2018-03-20-react-v-16-3.md +++ b/content/blog/2018-03-20-react-v-16-3.md @@ -3,7 +3,7 @@ title: "React v16.3.0: New lifecycles and context API" author: [bvaughn] --- -This release includes a new class component lifecycle (`getDerivedStateFromProps`), a new `StrictMode` component, an official context API, a new ergonomic ref API, and a ref-forwarding API! +This release includes an official context API, new class component lifecycles, a new `StrictMode` component, a new ergonomic ref API, and a ref-forwarding API! For the past few months, the React team has been working on support for [asynchronous rendering](/blog/2018/03/01/sneak-peek-beyond-react-16.html). We are excited about the new features it will enable. @@ -64,7 +64,7 @@ For example, with the current API, it is too easy to block the initial render wi Many of these issues are exacerbated by a subset of the component lifecycles (`componentWillMount`, `componentWillReceiveProps`, and `componentWillUpdate`). These also happen to be the lifecycles that cause the most confusion within the React community. For these reasons, we are going to deprecate those methods in favor of better alternatives. -We recognize that this change will impact many existing components. (At Facebook, we maintain more than 50,000 React components, and we can't tell our engineers to rewrite them either.) Because of this, the migration path will be as gradual as possible, and will provide escape hatches. +We recognize that this change will impact many existing components. Because of this, the migration path will be as gradual as possible, and will provide escape hatches. (At Facebook, we maintain more than 50,000 React components. We depend on a gradual release cycle too!) > **Note:** > @@ -72,7 +72,9 @@ We recognize that this change will impact many existing components. (At Facebook > > Even in version 17, it will still be possible to use them, but they will be aliased with an "UNSAFE_" prefix to indicate that they might cause issues. We have also prepared an [automated script to rename them](https://github.com/reactjs/react-codemod#rename-unsafe-lifecycles) in existing code. -We are also adding a new static lifecycle, `getDerivedStateFromProps`, as a safer alternative to the legacy `componentWillReceiveProps`. +In addition to deprecating unsafe lifecycles, we are also adding a couple of new lifecyles: +* [`getDerivedStateFromProps`](/docs/react-component.html#static-getderivedstatefromprops) is being added as a safer alternative to the legacy `componentWillReceiveProps`. +* [`getSnapshotBeforeUpdate`](/docs/react-component.html#getsnapshotbeforeupdate) is being added to support safely reading properties from e.g. the DOM before updates are made. [Learn more about these lifecycle changes here.](#TODO-link-to-update-on-async-blog-post) diff --git a/content/docs/reference-react-component.md b/content/docs/reference-react-component.md index 5224116e..54df91bf 100644 --- a/content/docs/reference-react-component.md +++ b/content/docs/reference-react-component.md @@ -295,9 +295,13 @@ If you need to update `state` in response to `props` changes, use `UNSAFE_compon ### `getSnapshotBeforeUpdate()` -`getSnapshotBeforeUpdate()` is invoked right before the most recently rendered output is committed to e.g. the DOM. It enables your component to capture current values (e.g. scroll position) before they are potential changed. +`getSnapshotBeforeUpdate()` is invoked right before the most recently rendered output is committed to e.g. the DOM. It enables your component to capture current values (e.g. scroll position) before they are potential changed. Any value returned by this lifecycle will be passed as a parameter to `componentDidUpdate()`. -Any value returned by this lifecycle will be passed as a parameter to `componentDidUpdate()`. +For example: + +`embed:react-component-reference/get-snapshot-before-update.js` + +In the above examples, it is important to read the `scrollHeight` property in `getSnapshotBeforeUpdate` rather than `componentWillUpdate` in order to support async rendering. With async rendering, there may be delays between "render" phase lifecycles (like `componentWillUpdate` and `render`) and "commit" phase lifecycles (like `getSnapshotBeforeUpdate` and `componentDidUpdate`). If a user does something like resize the browser during this time, a `scrollHeight` value read from `componentWillUpdate` will be stale. * * * diff --git a/examples/react-component-reference/get-snapshot-before-update.js b/examples/react-component-reference/get-snapshot-before-update.js new file mode 100644 index 00000000..e8d8d299 --- /dev/null +++ b/examples/react-component-reference/get-snapshot-before-update.js @@ -0,0 +1,27 @@ +class ScrollingList extends React.Component { + listRef = React.createRef(); + + getSnapshotBeforeUpdate(prevProps, prevState) { + // Are we adding new items to the list? + // Capture the current height of the list so we can adjust scroll later. + if (prevProps.list.length < this.props.list.length) { + return this.listRef.current.scrollHeight; + } + return null; + } + + componentDidUpdate(prevProps, prevState, snapshot) { + // If we have a snapshot value, we've just added new items. + // Adjust scroll so these new items don't push the old ones out of view. + if (snapshot !== null) { + this.listRef.current.scrollTop += + this.listRef.current.scrollHeight - snapshot; + } + } + + render() { + return ( +
{/* ...contents... */}
+ ); + } +}