Before upgrading react to version 16.3, I'd call a method based on changes in props like this :
componentWillReceiveProps(nextProps){
if(this.props.country.length !== nextProps.country){
doSomething(); //example calling redux action
}
}
componentWillReceiveProps is unsafe on Version 16.3 and we must use getDerivedStateFromProps. However, this method returns an object and I don't know how I can call a method from inside it the same way I do with componentWillReceiveProps
Yes, you need to return an object, which is the new state that that is derived from nextProp. According to docs:
getDerivedStateFromProps should return an object to update state, or null to indicate that the new props do not require any state updates.
But since you are not updating your state in any way inside your componentWillReceiveProps, you should use componentDidUpdate instead of getDerivedStateFromProps:
componentDidUpdate(prevProps){
if ( prevProps.country !== this.props.country.length ) {
doSomething(); //example calling redux action
}
}
For this situation, it was good for the OP to use componentDidUpdate but I found myself needing getDerivedStateFromProps so I had to make my custom function static as well and call it using the class' name inside getDerivedStateFromProps. Something like this:
componentDidMount() {
const something = ClassComponentName.runThisFunction();
this.setState({ updatedSomething: something });
}
static getDerivedStateFromProps(nextProps, prevState) {
if (nextProps.key !== prevState.key) {
return {
updatedSomething: ClassComponentName.runThisFunction()
};
}
return null;
}
static runThisFunction() {
//do stuff and return value
}
To clarify, this is updating the component's state on load as well as when new props arrive. This definitely took me back to my typed-language days. Hope it helps!
if you need to call a function in "getDerivedStateFromProps", you can put this function in state in constructor , then get this function in "getDerivedStateFromProps" from state.
put function in state in constructor:
constructor(props){
super(props);
this.state = {
func1:this.func1.bind(this)
}
}
get function from state in getDerivedStateFromProps:
getDerivedStateFromProps(props,state){
return {
model:state.func1(props.model)
}
}
Related
I just came in react after an year and before that I used to use componentWillRecieveProps() to call api(fire an action) just after getting updated props.
componentWillRecieveProps(nextProps) {
if (nextProps.user !== this.props.user) {
//Some api call using user prop
}
}
But now componentWillRecieveProps is replaced by getDerivedStateFromProps and there I cannot use this inside it. So how can I dispatch an event in newer react version or what is the best way?
static getDerivedStateFromProps(nextProps, prevState) {
if (nextProps.user !== prevState.user) {
this.fetchSetting();
return { user: nextProps.user };
}
return null;
}
fetchSetting = async () => {
const { fetchSetting } = this.props;
const data = await fetchSetting();
};
You can use the method componentDidUpdate(prevProps, prevState) which is a good replacement for componentWillReceiveProps().
Check the documentation here : componentDidUpdate (React.Component)
In you exemple you can do this :
static componentDidUpdate(prevProps, prevState) {
if (this.props.user !== prevProps.user) {
this.fetchSetting();
return { user: this.props.user };
}
return null;
}
But actually, if you really want to match the latest recommendations of React you shouldn't use classes but hooks which is aimed to be the new replacement. You can find more information about hooks on the page : Introducing Hooks
There are two ways you can achieve this: you can use the new useEffect hook or you can use componentDidUpdate to compare the props manually and call a method that updates the state based on that.
The preferred way by the React team is the functional way (yea I know it's weird) using this:
https://reactjs.org/docs/hooks-effect.html
If you want to keep using the class-based way then you can use componentDidUpdate:
https://reactjs.org/docs/react-component.html#componentdidupdate
I want to set the local state of a component using props obtained from mapStateToProps. When I use this.setState in ComponentWillMount() method or ComponentDidMount() method, it is undefined.
componentWillMount() {
this.props.fetchBooks(this.props.id);
this.setState({
books:this.props.books
})
}
const mapStateToProps = (state, ownProps) => {
let id = ownProps.match.params.book_id;
return {
id: id,
books: state.library.books,
};
};
The 'books' data is retrieved using the fetchBooks() function obtained by mapDispatchToProps.
How can I set the sate using the props obtained from mapStateToProps?
The problem might be that this.props.fetchBooks is an asynchronous operation. In that case, this.setState is called before the operation is completed, hence the undefined value.
But why do you want to store the books in the local state? Why don't you use directly the books prop instead?
Using derived state is usually unnecessary, and might be a bad idea (see this blog post from the official React website for an in-depth explanation).
If you really need to store the books in the local state, you could:
if fetchBooks returns a promise, use then or await (and move the code in componentDidUpdate as suggested by #Baruch)
use getDerivedStateFromProps
Your componentWillMount lifecycle method will only fire once, so using it to call the function that fetches the data and also use the data will most likely not work. You should use componentWillReceiveProps instead.
constructor(props) {
props.fetchBooks(props.id);
}
componentWillReceiveProps(nextProps) {
if (nextProps.books != this.props.books) {
this.setState({books: nextProps.books});
}
}
You better use straight inside your render() {} this.props.assignedSupervisors instead of putting it in a class state.
Otherwise use
componentDidUpdate(prevProps, prevState) {
if (this.props.assignedSupervisors && this.props.assignedSupervisors !== prevProps.assignedSupervisors) {
this.setState({
supervisors:this.props.assignedSupervisors
})
}
}
I've read the documentation on reactjs.org regarding getDerivedStateFromProps. I've seen the use cases. And I understand why to use it.
But I cannot figure out how it deals with the return value. Hence my question, when it does return... where does it go?
It doesn't setState because it does not have access to this.
To set state, requires using componentDidUpdate and looking for changes, then setting state.
Assume the following code:
public static getDerivedStateFromProps: IArrowFunction = (nextProps: IMyContainerProps, prevState: IMyContainerState) => {
if (nextProps.havingFun !== prevState.havingFun) {
console.log('[MyContainer.tsx] getDerivedStateFromProps :::::CHANGED::::::', nextProps, prevState);
return { havingFun: nextProps.havingFun };
} else { return null; }
}
So what does React do with that return ^?
I could then setState on componentDidMount. But this does not appear to have anything to do with getDerivedStateFromProps. Additionally this lifecycle method triggers every time. And it forces a re-render.
public componentDidUpdate(prevProps: IMyContainerProps, prevState: IMyContainerState): void {
if (prevState.havingFun !== this.props.havingFun) {
console.log('[MyContainer.tsx] componentDidUpdate *******CHANGED******', prevState, prevProps, this.props);
this.setState({ havingFun: this.props.havingFun });
}
}
At what point does the return from getDerivedStateFromProps come into play?
UPDATED: this lifecycle method will actually update state if properly configured as above. You do not need an additional method to setState
The return value is similar in concept like setState:
return { havingFun: nextProps.havingFun };
Where you can assume havingFun a state property and the value nextProps.havingFun is updated value.
When you use return null it means you are not doing anything with the state.
Note: getDerivedStateFromProps is really different concept than setState though I have tried here to explain it the way only.
You should read the docs for more detail:
getDerivedStateFromProps is invoked right before calling the render method, both on the initial mount and on subsequent updates. It should return an object to update the state, or null to update nothing.
It's returned to state when the parent component re-renders.
React 16 deprecates componentWillReceiveProps() lifecycle method. The preferred replacement is new getDerivedStateFromProps() or componentDidUpdate(). Now let's suppose I have some code like that:
componentWillReceiveProps(newProps) {
if (this.props.foo !== newProps.foo) {
this.setState({foo: newProps.foo}, () => this.handleNewFoo()});
}
}
I could try moving the code to getDerivedStateFromProps() like that:
getDerivedStateFromProps(newProps, prevState) {
if (this.props.foo !== newProps.foo) {
return {foo: newProps.foo};
} else {
return null;
}
}
but what do I do with the callback from setState()? Is moving it to componentDidUpdate the only option? I'd rather have this.handleNewFoo() invoked before render() to avoid visual and performance cost of two renders.
If you haven't read this blog post you should
https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html#when-to-use-derived-state
If you are simply assigning props.foo to state.foo without any calculation / processing then you need to ask yourself should you really need that field in state. Because you can always use this.props.foo instead of this.state.foo.
what is this.handleNewFoo method does?
are you doing another setState inside handleNewFoo? if you are then you are triggering multiple render calls.
eg.
this.setState({foo: this.props.foo} // one render call, () => this.handleNewFoo())
const handleNewFoo = () => {
this.setState({ }) // another render call
}
If you are not doing any setState inside handleNewFoo then ask yourself does handleNewFoo has to be called on prop change?
If you are using setState inside the handleFoo i would suggest something like this
getDerivedStateFromProps(newProps, prevState) {
if (this.props.foo !== newProps.foo) {
return this.handleNewFoo(this.props.foo, prevState);
} else {
return prevState;
}
}
handleNewFoo(foo, state) {
// do some calculation using foo
const derivedFoo = state.foo + foo;
// if your are using immutability_helper library.
const derivedState = update(state, { foo: {$set: derivedFoo}});
return derivedState
}
It all depends on what you are doing inside this.handleNewFoo
EDIT:
Above code won't work as #Darko mentioned getDerivedStateFromProps is static method and you cannot access this inside it. And you cannot get the previous props inside getDerivedStateFromPropslink. So this answer is completely wrong.
one solution is to use useEffect
useEffect(() => {
setState(...)
}, [props.foo])
this useEffect will call whenever the props.foo is changed. And also the component will be rendered twice one for prop change and another for setState inside useEffect. Just be careful with setState inside useEffect as it can cause infinite loop.
I am working on an application and when i had the ...this.state in my componentWillRecieveProps my code was not working correctly.
I am not 100% sure why this was affecting my state. Is it because i am always appending the current state when theres no need to do that.
componentWillReceiveProps(nextProps) {
// this.setState({ ...this.state, ...nextProps })
this.setState({...nextProps})
}
The componentWillReceiveProps lifecycle function is deprecated. Please use the getDerivedStateFromProps static method instead. In your case it will look like this:
class Example extends React.Component {
state = {
...
}
static getDerivedStateFromProps(nextProps) {
return {...nextProps}
}
render() {
...
}
}
However in real life it is aimless to convert every props to state without using any logic. In this case it is better to reach the props directly via this.props.