With the release of React 16.3, some new lifecycle methods have been introduced, and release of React 17 will deprecate some lifecycle method.
getDerivedStateFromProps
is one of those newly introduced lifecycle method replacing componentWillReceiveProps
, which has now become UNSAFE_componentWillReceiveProps
.getDerivedStateFromProps
is a static method which is invoked after a component is instantiated as well as when it receives new props. Since it is a static method, you cannot access this
inside this method neither you can access any other class method. Unlike componentWillReceiveProps
you cannot set state inside this method, so the only way to update state is returning an object. If you don’t want to update any state, simply return null
.Let’s dive into some code
This is how
componentWillReceiveProps
works.componentWillReceiveProps(nextProps){
if(nextProps.someValue!==this.props.someValue){
//Perform some operation
this.setState({someState: someValue });
this.classMethod();
}
}
We compare
nextProps.someValue
with this.props.someValue
and if both are different then we perform some operation, setState
and call this.classMethod();
.Now let’s have a look how
getDerivedStateFromProps
works.static getDerivedStateFromProps(nextProps, prevState){
if(nextProps.someValue!==prevState.someValue){
return { someState: nextProps.someValue};
}
else return null;
}
componentDidUpdate(prevProps, prevState) {
if(prevProps.someValue!==this.props.someValue){
//Perform some operation here
this.setState({someState: someValue});
this.classMethod();
}
}
It receives two params
nextProps
and prevState
. As mentioned previously you cannot access this
inside this method so you’ll have to store the props in the state to compare the nextProps
with previous props. In above code nextProps
and prevState
are compared, if both are different then an object will be returned to update the state otherwise null
will be returned indicating state update not required. If state changes then componentDidUpdate
is called where we can perform the desired operations as we did in componentWillReceiveProps
.Let’s make it more clear using an example
Let’s say we’re getting some data from firebase and displaying it in the form of stats. Here’s the code for the same.
import React, {PureComponent} from "react";
import DisplayStat from "./displayStat.js"
class App extends PureComponent{
constructor(){
super();
this.state={
path : "path-1"
}
}
changePath=()=>{
this.setState({path: "path-2"});
}
render(){
return(
<div>
<DisplayStat path={this.state.path} />
<div onClick={this.changePath} >Change Path</div>
</div>
)
}
}
import React, {PureComponent} from "react";
class DisplayStat extends PureComponent{
constructor(props){
super();
this.state={
firebaseRef: firebase.database().ref(this.props.path);
}
}
componentDidMount() {
this.getData(this.state.firebaseRef);
}
componentWillReceiveProps(nextProps){
if(nextProps.path!==this.props.path){
let {firebaseRef}=this.state;
firebaseRef.off("value"); //Turn off the connection to previous path.
firebaseRef=firebase.database().ref(nextProps.path);
this.setState({firebaseRef, path :nextProps.path });
this.getData(firebaseRef);
}
}
getData=(ref)=>{
// open connection and listen to firebase path
ref.on("value", snapshot => {
//Perform some operation
});
}
render(){
return(
<div>
//Display Stats
</div>
);
}
}
The above example uses
componentWillReceiveProps
. Initially, the displayStat.js
component will listen to firebase on path-1
, when a user clicks on the Change Path button the state will change in the App.js
file and componentWillReceiveProps
will be called in the displayStat.js
file. The previous connection to firebase path will be closed, and a new will get created. Notice we’re passing firebase reference as parameters to getDate()
to listen to firebase.Now let’s do the same thing using
getDerivedStateFromProps
.import React, {PureComponent} from "react";
class DisplayStat extends PureComponent{
constructor(props){
super();
this.state={
path: this.props.path,
firebaseRef: firebase.database().ref(this.props.path);
}
}
componentDidMount() {
this.getData(this.state.firebaseRef);
}
componentDidUpdate(prevProps, prevState) {
if (prevState.path !== this.state.path) {
let firebaseRef=firebase.database().ref(this.state.path);
this.setState({firebaseRef});
this.getData(firebaseRef);
}
}
static getDerivedStateFromProps(nextProps, prevState){
if(nextProps.path!==prevState.path){
let firebaseRef=prevState.firebaseRef;
firebaseRef.off("value"); //Turn off the connection to previous path.
// We can't do this here as we can't access `this` inside this method.
// firebaseRef=firebase.database().ref(nextProps.path);
// this.setState({firebaseRef, path :nextProps.path });
// this.getData(firebaseRef);
return {path : nextProps.path};
}
else return null;
}
getData=(ref)=>{
// open connection and listen to firebase path
ref.on("value", snapshot => {
//Perform some operation
});
}
render(){
return(
<div>
//Display Stats
</div>
);
}
}
Notice an object is being returned in the
getDerivedStateFromProps
to update the state and no class method is being called. We’re using componentDidUpdate
to check if a path is changed or not and accordingly create a new firebase connection and listen to new path.Thanks for reading this article. Please hit the Clap button if you like it.