I'm refactoring the deprecated life-cycle method componentWillRecieveProps() with its new successor static getDerivatedPropsFromState()
The problem that I'm facing with this refactor is that componentWillRecieveProps() use a class function inside:
componentWillRecieveProps(nextProps) {
if(this.props.theme !== nextProps.theme) {
this.changeTheme()
}
}
So when I try to access this function inside of the new life-cycle method:
static getDerivatedPropsFromState(nextProps, prevState) {
if(prevState.theme !== nextProps.theme) {
this.changeTheme();
return { prevState: nextProps.theme };
}
return null;
}
An error jump saying this.changeTheme() is undefined.
How should I make reference to this function inside of static getDerivatedPropsFromState()?
Any help and explanation on why this is happening will be really appreciated.
getDerivatedPropsFromState is used for only updating the state. You should use componentDidUpdate in place of componentWillReceiveProps if you are planning to do updates.
See https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html#fetching-external-data-when-props-change
In the blog it mentions:
The recommended upgrade path for this component is to move data updates into componentDidUpdate. You can also use the new getDerivedStateFromProps lifecycle to clear stale data before rendering the new props.
So instead of
componentWillRecieveProps(nextProps){
if(this.props.theme !== nextProps.theme){
this.changeTheme()
}
}
One alternative is to do this
static getDerivatedPropsFromState(nextProps, prevState) {
if(prevState.theme !== nextProps.theme) {
return { theme: nextProps.theme };
}
return null;
}
componentDidUpdate(prevProps, prevState) {
if (this.state.theme !== prevState.theme) {
this.changeTheme();
}
}
Related
I like to update my code to use getDerivedStateFromProps instead of componentWillReceiveProps as the I am receiving deprecated error. The component is receiving a date prop and every time the date is changed in need to run the getList with the new date. To do this I am using the follow code below
componentWillReceiveProps(nextProps) {
const {date} = this.props;
if (nextProps.date !== date) {
console.log('prop changed to : ', nextProps.date);
this.getList(nextProps.date);
}
}
I tried the following but it does not work
static getDerivedStateFromProps(props, state) {
const {date} = this.props;
if (props.date !== date) {
console.log('prop changed to : ', props.date);
this.getList(props.date);
}
return;
}
getDerivedStateFromProps does not look like the right tool for what you are trying to do. Instead use componentDidUpdate:
componentDidUpdate(prevProps) {
const { date } = this.props;
if (prevProps.date !== date) {
this.getList(date);
}
}
It's pretty rare to use getDerivedStateFromProps. For more information on when to use getDerivedStateFromProps I recommend this article
I need to update a child's state when a prop gets updated, so I made something like this:
componentDidUpdate(prevProps) {
const { searchValue, searchCriterion } = this.props;
if (searchValue !== prevProps.searchValue) {
this.setState({ searchValue });
}
if (searchCriterion !== prevProps.searchCriterion) {
this.setState({ searchCriterion });
}
}
ESLint's airbnb guide is complaining about it and throwing this warning, even though I can't see any noticeable rendering or performance issues.
The warning says:
Updating the state after a component update will trigger a second
render() call and can lead to property/layout thrashing.
Is there a better way to update a child's state when a prop has a new value?
Or should I ignore the warning?
The problem of your code is that it might create an infinite loop. When you call the setState method, you trigger a second render, just like the warning says, and consequently a new componentDidUpdate.
In order to solve this problem, you might want to create a break condition for certain values of your state to get out of your loop. For example, you could simply use a flag like so:
componentDidUpdate(prevProps) {
const { searchValue, searchCriterion } = this.props;
if (this.state.isAlreadyUpdated === true) {
this.setState({ isAlreadyUpdated: false });
break;
} else {
this.setState({ isAlreadyUpdated: true });
}
if (searchValue !== prevProps.searchValue) {
this.setState({ searchValue });
}
if (searchCriterion !== prevProps.searchCriterion) {
this.setState({ searchValue });
}
}
Good day,
I'm trying to fetch a new data once a new props has changed on my route.
Here's my sample routing:
<Route path={'/students/:selectedPage'} exact component={Students} />
Basically, I have a method that fetches my data. So I'm invoking it in my componentDidMount() Here are my sample codes:
componentDidMount(): void {
this.getData()
}
getData(selectedPage){
axios.get(`http://localhost:1343/students/${selectedPage}`).then(response=>{
this.setState({
students: response.data
})
}).catch(error=>console.log(error)
}
For my componentDidUpdate method which trigger if there's new changes in the param of my url.
componentDidUpdate(): void {
if (this.props.match.params.selectedPage !== prevProps.selectedPage){
this.getData(this.props.match.params.selectedPage)
}
}
Unfortunately, it causes to have infinite request from the web api. Which makes the table laggy. I tried to create a state with a name, hasLoaded but it gives me an error message that says, infinite loop has detected.
Any advice?
Compare your Props in ComponentWillReceiveProps like this,
shouldComponentUpdate: function(nextProps, nextState) {
return nextProps.selectedPage != this.props.selectedPage ;
}
componentWillReceiveProps(nextProps) {
if (nextProps.selectedPage !== this.props.selectedPage ) {
//this.setState({ selectedPage : nextProps.selectedPage })
this.getData(nextProps.selectedPage)
}
}
or Do this instead Keep your selectedPage in state
static getDerivedStateFromProps(nextProps, prevState) {
if (nextProps.selectedPage !== prevState.selectedPage ) {
return { selectedPage : nextProps.selectedPage };
}
else return null;
}
componentDidUpdate(prevProps, prevState) {
if (prevProps.selectedPage !== this.props.selectedPage ) {
//Perform some operation here
//this.setState({ selectedPage : this.props.selectedPage });
this.getData(this.props.selectedPage)
}
}
```
I want to use getderivedstatefromprops to update the state of selectedPlan when it receives a different number from the prop defaultPlan.
I have tried to convert componentDidMount to getderivedstatefromprops, but getderivedstatefromprops does not seem to be getting called in my component?
state = {
selectedPlan: 0,
};
static getderivedstatefromprops(props, state){
if (props.defaultPlan !== state.selectedPlan) {
return{
selectedPlan: props.defaultPlan
};
}
return null;
}
componentDidMount() {
if (this.props.plans.length > this.props.defaultPlan) {
this.setState({ selectedPlan: this.props.defaultPlan });
}
}
I am using this in a PureComponent, and I'm not sure if thats the reason why it is not working?
componentWillReceiveProps(nextProps) {
if (
**this.state.clicked** &&
this.props.something &&
nextProps.addSubtract
) {
this.setState({ valid: nextProps.isValid });
}
if (!this.props.someItems) {
this.setState({ products: nextProps.propsValues});
}
if (nextProps.valueOfProps && **this.methodOnClass**) {
..........
..........
}
}
The code above is similar to a new project I'm working on and I have encountered a road-block. Since componentWillReceiveProps is deprecated and I need to replace a lot of code inside it with this.method and this.state , is there a way to access these in getDerivedStateFromProps without moving a lot of logic in other lifecycle methods.
First of all getDerivedStateFromProps is not a replacement of componentWillReceiveProps. See this post for more detail.
To return the state by using getDerivedStateFromProps, you simply return an object.
Example:
return {
myState: 'updated state'
}
If no condition match, simply return null:
return null
Similar to setState example:
setState({myState: 'updated state'})