What is React getSnapshotBeforeUpdate
Since the release of React Suspense, rendering components are becoming more asynchronous.
This is a good thing for folks with limited bandwidth or weak devices.
In a previous article I wrote about doing DOM manipulation within the React componentDidUpdate
lifecycle.
This was a good solution to do DOM manipulation because it was the final commit lifecycle of a React component.
But that won’t be the case any longer since lazy loading React components may cause a delay in rendering elements.
The new lifecycle method in React
getSnapshotBeforeUpdate(prevProps, prevState) {}
This method may look familiar to the componentDidUpdate
lifecycle. It’s given the previous props and the previous state, but it has 1 major difference.
getSnapshotBeforeUpdate
gets called before the most recent render()
output.
It allows the engineer to capture some information about the DOM before it’s changed.
This method should return a value or null
.
How getSnapshotBeforeUpdate works with componentDidUpdate
componentDidUpdate(prevProps, prevState, snapshot) {
console.log(snapshot) // undefined
}
If you see the code example above, snapshot will be undefined.
To make it have a value, you must use the getSnapshotBeforeUpdate
method and return a value.
getSnapshotBeforeUpdate() {
return {foo: 1};
}
componentDidUpdate(prevProps, prevState, snapshot) {
console.log(snapshot) // { foo: 1 }
}
As you can see in the code above, I’m using getSnapshotBeforeUpdate
and returning an object.
{ foo: 1 }
I then print out the snapshot variable within the componentDidUpdate
method and you will see the object that was return in getSnapshotBeforeUpdate
.
When to use getSnapshotBeforeUpdate
As mentioned before this is a great method to capture some information about the DOM before it’s changed.
Let’s look at a simple example.
The goal is to override the box color whenever the user goes from biggest box size to any of the other smaller sizes.
class App extends React.Component {
state = {
boxSize: "normal"
};
// Defines box sizes with background color
boxes = {
small: {
height: 60,
width: 60,
backgroundColor: "yellow"
},
normal: {
height: 120,
width: 120,
backgroundColor: "red"
},
big: {
height: 180,
width: 180,
backgroundColor: "blue"
}
};
// Get box DOM reference
boxRef = React.createRef();
handleClick = value => () => this.setState({ boxSize: value });
getSnapshotBeforeUpdate() {
// Let componentDidUpdate know whether to override the box
// color or not.
return {
overrideBoxColor: this.boxRef.current.offsetHeight > 120
};
}
componentDidUpdate(prevProps, prevState, snapshot) {
// Override the box ref directly
if (snapshot.overrideBoxColor) {
this.boxRef.current.style.backgroundColor = '#000';
}
}
render() {
return (
<>
<div>
<button onClick={this.handleClick("small")}>Shrink</button>
<button onClick={this.handleClick("normal")}>Normal</button>
<button onClick={this.handleClick("big")}>Size up</button>
</div>
<div ref={this.boxRef} style={this.boxes[this.state.boxSize]} />
</>
);
}
}
If you’d like a better example, check out the React docs.
Happy coding!
I like to tweet about React and post helpful code snippets. Follow me there if you would like some too!