I have an React application that has the following structure:
component A is composed of B and C
When the component B calls it's componentDidMount method, is this true that all component finished mounting?
Or in other words does React fire componentDidMount after all components in the tree were mounted?
or e.g. Components B componentDidMount is called when component A mounted?
According to the documentation, the order of the lifecycle methods on first mount is as follows:
constructor()
componentWillMount()
render()
componentDidMount()
Let's say you have this component:
class A extends Component {
render() {
return (
<div>
<B />
<C />
</div>
)
}
}
When A is mounted, it will fire componentDidMount(). That will happen after render. Since B and C do not exist before A's render() is called, the completion of A's mounting requires that B and C finish their respective lifecycles. A's componentDidMount() will fire after B and C are mounted. A's componentWillMount() fires before A's render(), and therefore it also fires before B or C are mounted
UPDATE
As of React 16.3, componentWillMount starts the deprecation process, along with componentWillUpdate and componentWillReceiveProps. The above example will work fine in any 16.x release of react, but it will get deprecation warnings. There are new methods that take place of the deprecated ones, with their own lifecycle. More about them in the component API docs. Here is a cheatsheet diagram for the new lifecycles
Parent's componentDidMount fires after children's.
Similar issue: In which order are parent-child components rendered?
The React docs state:
componentWillMount() is invoked immediately before mounting occurs. It is called before render()...
Each component will fire its own componentDidMount. A will its own, then B, then C.
So I guess the answer to your question is, no, not all components would have finished mounting, s they fire the life cycle method 'immediately before mounting'.
Related
Having read a bunch of articles on the web about shouldComponentUpdate & render I want to double check if I get it correct when components are rerendered (render method is called) and when shouldComponentUpdate is called.
React docs (and dozens or articles say) that shouldComponentUpdate is called ONLY when new props are received or there is new state. But is seems that PureComponent does the same at first glance...
So to investigate it I wrote sample app:
parent component
import React, { Component } from 'react';
import './App.css';
import Hello from './Hello';
class App extends Component {
objWithName = { name: 'World' };
state = {
date: Date.now()
}
componentDidMount() {
setInterval(() => {
this.setState({ date: Date.now() });
}, 2000);
}
render() {
return (
<div className="App">
<p>Rendering timestamp {this.state.date}</p>
<Hello name={this.objWithName} />
</div>
);
}
}
export default App;
child component
import React from 'react';
export default class Hello extends React.Component {
shouldComponentUpdate() {
console.log('shouldComponentUpdate called');
return true;
}
render() {
console.log('render called');
return <p>Hello {this.props.name.name}</p>
}
}
So my first question is: is it completely true? I mean: In above code snippets, parent component in setInterval calls setState just to trigger its update, but this state is not used anywhere. And after doing that, child component is rerendered (render is called) & shouldComponentUpdate is called even though nothing has changed for him (it didn't receive any new props, nor state). I didn't find any explanation for this behaviour in React docs so I'm not sure how it works. What is more, if that child component didn't have any input props at (simply render static string) it would also get rerendered. Can sb explain it?
So my second question is: what does it mean new props/state is received by the component? Does it mean that object value is changed (for primitives simply new value, and for objects new reference)?
Third thing: assuming that a change in parent top most component (e.g. App.js) in the application happens (new prop or new state), does it mean that by default ALL react component that are currently rendered/mounted (even leafs that do not have any state, nor props that were changed) will rerender?
shouldComponentUpdate is just called from setState and forces render when returns true (default behaviour) - and updating DOM when different. This is by design to have a lifecycle/flow. When shouldComponentUpdate returns false then you can avoid unnecessary, usually costly render processing (and DOM update). PureComponent is just an optimized, ready to use component with shouldComponentUpdate defined to shallowly compare props (by comparing references).
React doesn't care if props/state are used, not using observables - you can use mobx for that.
New props means any change - it's shouldComponentUpdate responsibility to check swallowly or deep, depends what you need.
Yes, all children will be updated (forced to refresh node state/view in virtual DOM). It's fast/optimized process (operating on virtual tree) but they should use shouldComponentUpdate to limit theirs rerendering (and final DOM updates).
I recently wanted to upgrade my knowledge of React, so I started from the component lifecycle methods. The first thing that got me curious, is this componentWillReceiveProps. So, the docs are saying that it's fired when component is receiving new (not necessarily updated) props. Inside that method we can compare them and save into the state if needed.
My question is: Why do we need that method, if changes in props of that component (inside parent render) will trigger the re-render of this child component?
One common use case are state (this.state) updates that may be necessary in response to the updated props.
Since you should not try to update the component's state via this.setState() in the render function, this needs to happen in componentWillReceiveProps.
Additionally, if some prop is used as a parameter to some fetch function you should watch this prop in componentWillReceiveProps to re-fetch data using the new parameter.
Usually componentDidMount is used as a place where you trigger a method to fetch some data. But if your container, for example, UserData is not unmounted and you change userId prop, the container needs to fetch data of a user for corresponding userId.
class UserData extends Component {
componentDidMount() {
this.props.getUser(this.props.userId);
}
componentWillReceiveProps(nextProps) {
if (this.props.userId !== nextProps.userid) {
this.props.getUser(nextProps.userId);
}
}
render() {
if (this.props.loading) {
return <div>Loading...</div>
}
return <div>{this.user.firstName}</div>
}
}
It is not a full working example. Let's imagine that getUser dispatch Redux action and Redux assign to the component user, loading and getUser props.
It 'serves' as an opportunity to react to the incoming props to set the state of your application before render. If your call setState after render you will re-render infinitely and that's why you're not allowed to do that, so you can use componentWillReceiveProps instead.
But... you are beyond CORRECT in your confusion, so correct in fact that they are deprecating it and other Will-lifecycle hooks Discussion Deprecation.
There are other ways to accomplish what you want to do without most of those Will-lifecycle methods, one way being don't call setState after render, just use the new incoming props directly in render (or wherever) to create the stateful value you need and then just use the new value directly, you can then later set state to keep a reference for the next iteration ex: this.state.someState = someValue, this will accomplish everything and not re-render the component in an infinite loop.
Use this as an opportunity to react to a prop transition before render() is called by updating the state using this.setState(). The old props can be accessed via this.props. Calling this.setState() within this function will not trigger an additional render.
Look at this article
the componentWillReceiveProps will always receive as param "NxtProps", componentWillReceiveProps is called after render().
some people use this method use this to compare nxtProps and this.props to check, if something should happen before the component call render, and to some validations.
check the react's documentation to know more about react lifecycle!
hope this could help you!
changes in props of that component (inside parent render) will trigger the re-render of this child component
You are absolutely right. You only need to use this method if you need to react to those changes. For instance, you might have a piece of state in a child component that is calculated using multiple props.
Small Example:
class Test extends Component {
state = {
modified: "blank"
};
componentDidMount(){
this.setState({
modified: `${this.props.myProp} isModified`
});
}
componentWillReceiveProps(nextProps) {
this.setState({
modified: `${nextProps.myProp} isModified`
});
}
render() {
return <div className="displayed">{this.state.modified}</div>
}
}
In this example, componentDidMount sets the state using this.props. When this component receives new props, without componentWillReceiveProps, this.state.modified would never be updated again.
Of course, you could just do {this.props.myProp + "IsModified"} in the render method, but componentWillReceiveProps is useful when you need to update this.state on prop changes.
The react docs mention that calls to setState are enqueued, and do not happen immediately. Does react make any guarantees that setState enqueued inside componentWillReceiveProps will execute before the next component render? Are either of these scenarios more likely than the other?
props change > componentWillReceiveProps called > setState enqueued > setState runs > render (which includes new state)
props change > componentWillReceiveProps called > setState enqueued > render > setState runs > re-rendered
Or, are both of these scenarios equally likely? Meaning does React not make any guarantees when setState will run relative to component lifecycle methods?
Here is a ES2015 code excerpt of my example:
import React from 'react';
class Widget extends React.Component {
componentWillReceiveProps() {
this.setState({foo: 'bar'});
}
render() {
return <div>
<a onClick={(e) => {
e.preventDefault();
this.props.triggerExternalPropsChange();
}}>
Click me to trigger new props
</a>
</div>;
}
}
Where triggerExternalPropsChange passes new props to the Widget component.
The only reason componentWillReceiveProps exists is to give the component an opportunity to setState. So yes, any state you set synchronously in it will be processed together with the new props. There won’t be two renders in this case, just one.
It's 1.
Calling setState() in componentWillReceiveProps() is an exception in the sense of executing state update before the component renders, so you will get both props changes and state changes applied in the same render.
Yep, both are likely. React will try to render anytime it gets new props or state and because it does dom diffing, it tries to render as often as possible. You have options to control it though, using shouldComponentUpdate you can check and wait until both props and state have been updated before rendering.
I'm using React Router 4.
When I render component with render parameter componentWillReceiveProps() it doesn't fire the fist time, so I need to click twice to sent props to the component.
I render like this:
const CartRoute = (props) => (<Cart itemsInCart = {this.state.itemsInCart} deleteItemFromCart = {this.deleteItemFromCart} {...props} />);
.....
<Switch>
.....
<Route path="/cart" render={CartRoute} />
</Switch>
Without Router (when all components are on the same page) it works ok.
Here is detailed description:
React router - Need to click LINK twice to pass props to Component
I think Reason is simple one, As per DOC:
React doesn't call componentWillReceiveProps with initial props during
mounting. It only calls this method if some of component's props may
update. componentWillReceiveProps() is invoked before a mounted component receives new props.
componentWillReceiveProps will not get called when first time component get rendered, at that time componentDidMount get called, when you do any changes in props values then only componentWillReceiveProps will get triggered. So first time if you want to do some calculation do that in componentDidMount method, like this:
componentDidMount(){
console.log('props values', this.props); //it will print the props values
}
componentWillReceiveProps is a Updating lifecycle method not Mounting method.
Mounting Methods:
These methods are called when an instance of a component is being
created and inserted into the DOM.
Updating Methods:
An update can be caused by changes to props or state. These methods
are called when a component is being re-rendered.
Check the difference between Mounting and Updating lifecycle method.
Out of curiosity, I just wanna know what will happen if I use setState() function in constructor of a Class in React Native or ReactJS?
Such as:
constructor(props) {
super(props);
this.setState({title: 'new title'});
}
what's the lifecycle of React gonna happen?
I haven't read the code inside React. I am afraid it will some any damage when I write it that way.
What setState essentially does is to run a bunch of logic you probably don't need in the constructor.
When you go state = {foo : "bar"} you simply assign something to the javascript object state, like you would any other object. (That's all state is by the way, just a regular object local to every component).
When you use setState(), then apart from assigning to the object state react also rerenders the component and all its children. Which you don't need in the constructor, since the component hasn't been rendered anyway.
Error Message would be
Uncaught TypeError: Cannot read property 'VARIABLE_NAME' of null
Please see the following two jsfiddle snippets.
Case 1) Working solution jsfiddle
class Hello extends React.Component {
constructor(props) {
super(props);
this.state = {
name: 'world'
}
}
render() {
return <div>{this.state.name} </div>
}
}
ReactDOM.render(<Hello />, document.getElementById('container'));
Case 2) Not working solution
class Hello extends React.Component {
constructor(props) {
super(props);
this.setState({
name: 'hello'
});
}
render() {
return <div>{this.state.name} </div>
}
}
ReactDOM.render(<Hello />, document.getElementById('container'));
This happens:
-constructor (starts setState)
-render (fails - because state has no property 'name' yet)
-name is added to state (but too late - it has already rendered)
Conclusion:
My rule of thumb, inside constructor uses this.state = {} directly, other places use this.setState({ });
Constructor: Constructor is Used to initialize the state.
State : Components that contain local state have a property called "this.state".
SetState: React components have a method available to them called setState Calling "this.setState" causes React to re-render your application and update the DOM.you can also track of prevstate in setState
If you use setState in constructor you would get error like this:Can only update a mounted or mounting component. This usually means you called setState() on an unmounted component.
React have not restricted the use of setState in any lifecycle event.
React official docs link for state update
It was told that you cannot access state directly outside constructor .
So you are free to call setState anywhere .
Technically setState is meant to update the existing state with some new value passed within ,which react react handles in the next update cycle through batch process,so using console.log of state right after setState will give the stale value.
Now lets focus on what if we call setState in the constructor .
React will prepare the batched piece of code with the new state passed into the setState and trigger a update .
While react have not stopped you from doing this ,however it knows that doing so might land you up in trouble so leaves a nice message for you
Warning: setState(...): Can only update a mounted or mounting component. This usually means you called setState() on an unmounted component. This is a no-op. Please check the code for the component.
React proceeds with further loading of component but the update never reflects for this batch.
So conclusion : If you try to do so you might not end up with error ,but you will have to bear the undesirable behavior as these updates will reflect no where even if triggered .