Recently I took an online test where the following question was asked:
Which of the following methods is not executed while mounting a React Component?
constructor()
render()
componentWillReceiveProps()
componentDidMount()
I believe all of these methods will get executed while mounting a React Component. But I did select option 4. componentDidMount() even though it is wrong as I had to select an option and yes the online test said it is wrong. According to an article on Pluralsight all of the above methods will execute on mounting (componentWillReceiveProps() is deprecated and static getDerivedStateFromProps() should be used).
What I do not understand is
Is the question wrong?
Are the options wrong?
My understanding of the question is wrong?
I am confused. Please help me get the right perspective.
Thanks in Advance.
The documentation for componentWillReceiveProps says
is invoked before a mounted component receives new props.
It operates on a already mounted component receiving new props. A component being mounted cannot receive new props until it has initial props.
Also note that getDerivedStateFromProps is not a 1 for 1 replacement method. It is suggested as an alternative for operations that were typically done in componentWillReceiveProps, but they do not do the same thing.
Phases of React Life Cycle methods
Mounting
constructor
static getDerivedStateFromProps()
render()
componentDidMount()
Updating
static getDerivedStateFromProps()
shouldComponentUpdate()
render()
getSnapshotBeforeUpdate()
componentDidUpdate()
unmounting
componentWillUnmount()
You can check the official documentation for a better understanding - the-component-lifecycle
Related
I am looking for an explanation of parameters for each component method such as componentDidUpdate(). I see the link https://reactjs.org/docs/react-component.html#componentdidupdate but it does not provide any explanation of the parameters such as prevProps, prevState, and snapshot. Where can I find documentation that describes them?
Is my current understanding of the parameters correct?
prevProps: The props object before render() was called by a change in either state or props.
prevState: The state object before render() was called by a change in either state or props.
snapshot: ???
prevState and prevProps are the state and props from the previous render cycle, as opposed to this.state and this.props from the current render cycle.
The snapshot comes from getSnapshotBeforeUpdate
Any value returned by this lifecycle will be passed as a parameter to
componentDidUpdate().
You can find the react component documentation here.
Aside from the documentation there are a few good blog posts on the web explaining the various lifecycle methods, when to use them and how they work:
https://blog.logrocket.com/the-new-react-lifecycle-methods-in-plain-approachable-language-61a2105859f3/
https://engineering.musefind.com/react-lifecycle-methods-how-and-when-to-use-them-2111a1b692b1?gi=3ac3c7c8ff34
A far as I know there is no other, more specific documentation about lifeCycleMethods.
Parameters such as prevProps and prevState are pretty much self-explanatory. Even if someone isn't sure what they are, console.log(prevProps, prevState) could help. My assumption is that self-explanatory nature of these parameters is what makes them ommited from detailed explanation in docs.
On the other hand, snapshop which is not that much self-explanatory is explained:
If your component implements the getSnapshotBeforeUpdate() lifecycle (which is rare), the value it returns will be passed as a third “snapshot” parameter to componentDidUpdate(). Otherwise this parameter will be undefined.
I was trying to pass props both in App component (The root Component) and then to Header component from App itself.
I have used Life Cycle Hooks upto componentWillReceiveProps() in both App and Header Component.
componentWillMount(), render(), componentDidMount() are getting executed in both the Components in an expected order.
However, componentWillReceiveProps() is not executed at all even on passing props. This is a unExpected behaviour, since componentWillMount() was executed normally!
I shall be extremely thankful to know why is this happening ! Thank you :)
Kindly check the code sample from the below link:
https://codesandbox.io/s/r092xkpwjp
Please Note: Question has been updated, and it shows both scenarios now, new props being passed (in Header Component which works fine now) and no new props being passed as was previously the case in the question (in App Component which still shows why things were working unexpectedly).
I don't see why you expect your components to be updated as the The props being passed to them always stay the same and no new props have been passed to these at all, but generally you should use componentDidUpdate(prevProps, prevState).
componentWillReceiveProps() only gets invoked when the props passed to them are new props, different from the previous values. In the question this was not happening.
Note: The question has been updated now for it to work properly.
Also consider managing the state by static getDerivedStateFromProps(props, state), i.e.:
static getDerivedStateFromProps(props, state){
// just return the state
return {
isLoading: false,
money: props.money
}
}
- it's executed on init + on updates.
As stated in the official documentation (see https://reactjs.org/docs/react-component.html) the
componentWillReceiveProps()
lifecycle method is deprecated and should be avoided.
The reason why it is never called is that, to help user avoid it, React developers renamed it
UNSAFE_componentWillReceiveProps()
You should however avoid it, since they plan to deprecate that method
1.The main reason why the componentWillReceiveProps() was not being invoked was because my props passed to Header Component were not changing at all, I have been passing the same props again and again. And componentWillReceiveProps() gets executed only when the props being passed are different each time.
This is what my Header component looked at the time of asking this question.
<Header
menus={["home", "about", "services", "blog"]}
/>
The Header Component had only the menus prop as an array (at the time of asking this question) and no event was updating this menus prop , that's the reason why my
componentWillReceiveProps() was never invoked/called in the Header Component.
Note: To simply the things I now passed another prop to Header Component, and started to test my code on this prop instead of working with the array menus prop.
<Header
menus={["home", "about", "services", "blog"]}
prop={this.state.prop}
/>
And I am making my state.prop to update using an event handler:
// Dynamically sending Props
handlePropSending = () => {
this.setState({
...this.state,
prop: this.state.prop + 1
});
};
And as I am clicking on the button 'Sending Props to Header', the new props are sent to Header Component and our componentWillReceiveProps is being called and executed succefully.
And same was the issue with componentWillReceiveProps in the App Component
ReactDOM.render(, rootElement);
Since I was adding money prop (money={9199}), there actually is no Parent Component available for money prop to update it's value (which we could have passed to the App Component for it to invoke its componentWillReceiveProps method).
NOTE: The code is updated now and there are event handlers now to make sure the props keep updated and now the componentWillReceiveProps() method is indeed being successfully invoked.
componentWillReceiveProps demonstrated along with other life Cycle Hooks
LIKE THEY SAY :) ALL IS WELL THAT ENDS WELL :)
As far as I know these are the scenarios when react calls the render() method provided shouldComponentUpdate() is not implemented.
when your component get mounted initially
when state got changed using this.setState()
when your component receives new props
when this.forceUpdate() get called.
Is there any other scenarios that I am missing?
Yes there's one more case I can think of. When parent component is re-render.
Every time a component is re-render all its children get re-render too. Unless you implement shouldComponentUpdate method in the children.
Hope it helps.
when context gets changed render gets called
I am in the process of trying to debug a third-party component. What I see happening is that it expects to initialise an internal attribute in componentWillMount() and then make use of it in componentWillUpdate(). The React documentation says this about 'update' methods:
An update can be caused by changes to props or state. These methods are
called when a component is being re-rendered
That being said, should the code handle the possibility that componentWillUpdate() will be called before componentWillMount() or should I be digging to see what seems to be apparent cause of the inverted sequence?
We are using React 15.0.1
As you mentioned componentWillUpdate() will be called only when a component is being re-rendered. And componentWillMount() will be called right before the initial render (a component is mounted just once in its lifecycle). So there are no possibility componentWillMount() is called after componentWillUpdate().
A story:
I have a server rendering but some part of my app cannot be done there, since they use document(react-art library for drawing on a canvas).
I cannot render everything in the same from, because react will say that the code received from a server and and client one are not the same.
So my solution is to render some part of my app on the server, then render this part on a client and, in the next frame, render everything that is impossible to render on a client.
So I was thinking about using setState in componentDidMount and trigger DOM update, so it can contain rendered client part which cannot be rendered on a server, but eslint says it is not good to set state in componentDidMount. Logically I cannot say why it is bad in this case. Generally it is not good because it triggers DOM update, but in my case, this is what I actually need.
What would you suggested in this case?
Edit 1:
Fixed typo, I mean componentDidMount not componentDidUpdate.
Edit 2:
Here is the same issue, but they use changing state in componentDidMount as a workaround.
I've just coded a similar scenario and happily used componentDidMount disabling ESLint's warning. IMHO it is perfectly valid ONLY in universal rendering scenarios.
Why: Using setState in discouraged in componentDidMount because you'll trigger an additional, unnecessary render.
However in a universal scenario where you want to differ server and client behaviour, you'll want that additional render and in order to prevent 'could not reuse markup' errors, you'll want it just after react reconciles with the server rendered DOM. In brief: You'll render twice in any case.
I don't however recommend coding this behaviour in a leaf / dumb component because doing so would require the supposedly dumb component to have some knowledge of it's environment (client / server) and present a design problem. Creating a component that would set the props of the dumb component would be the obvious solution.
Try setting state in componentWillMount or componentWillUpdate.
Be careful with componentWillMount, it can also be called server side.
What i understand from your question is that after your component is mounted, data on server and client changes and you want to keep component in sync with changing data.
I recommend you have a look at the flux or redux architectures of react. For example flux is implemented in a way that when anything in component changes it triggers action and listens to the store. And when anything in store is changed then component will re render itself.
Please see this link About ReactJS - Component Life Cycle.
you should use from componentWillMount cycle. componentWillMount is executed before rendering, on both server and client side.
I want to know how to trigger components update after my app is mounted.
In React, the conventional way to "push" state onto a component is using props, not state. If your application needs to acquire information client-side and adjust component state accordingly, you should implement componentWillReceiveProps.
If you feel that the state rendered on the server and in-browser are of the same kind, and don't want the hassle of tracking which properties belong this.state v. this.props, I suggest something like the following:
componentWillReceiveProps(nextProps) {
this.setState( Object.assign({}, this.state, nextProps) );
}
This will merge the passed properties into the component state, so that they can be accessed using this.state.
Prevent usage of setState in componentDidMount.
Updating the state after a component mount will trigger a second render() call and can lead to property/layout thrashing.
The following patterns are considered warnings:
class MyComponent extends React.Component {
componentDidMount(){
this.setState({
data: data
});
}
}
The following patterns are not considered warnings:
class MyComponent extends React.Component {
constructor(){
this.setState({
data: data
});
}
componentDidMount(){
...
}
}