Components in React go through lifecycle and understanding it helps us know the exact action to perform at the different stages.
Three phases of the React component lifecycle
Mounting phase
Updating phase
Unmounting phase
Component mounting phase
The starting point for a React component is the mounting phase which includes creating, initializing, and integrating it into the Document Object Model (DOM). In React versions before 16.3, this phase depended on the deprecated componentWillMount() lifecycle method to execute these actions.
The recommended ways for handling this phase are:
Constructor: before a component mounts, its constructor is executed first. This initializes the data that the component will use and binds class methods to their instance.
class AppExample extends React.Component{ constructor(props){ super(props); this.state = {counter : 0} this.handleClick = this.handleClick.bind(this); } handleClick = () => { this.setState = ({count: this.state.count + 1}) } // jsx goes here }
render(): when the render() function is executed, it considers both this.props and this.state properties and creates React elements, portals, strings, numbers, booleans, nulls, or undefined values. The initial DOM is generated based on the instructions given in the render method. However, instead of being directly inserted into the actual DOM, a virtual DOM is created and used to update the DOM at a later time.
render(){ return( <p>{this.state.count}</p> <button onClick={this,handleClick}>increase count</button> ) }
componentDidMount():After the render() method is called, the componentDidMount() method is triggered. This is where data fetching, event listening, and DOM interaction occur. It's important to note that componentDidMount() is only called once after the component is inserted into the DOM.
Component Updating Phase
Once a component is mounted, the updating phase begins. This is when the component is re-rendered due to a change in its state or props. In this phase, React determines whether it needs to re-render anything by asking whether any changes have occurred. The new virtual DOM is compared against the older one to identify the differences and decide what to re-render.
The recommended ways for handling this phase are:
- static getDerivedStateFromProps(): during the updating stage, the component's state changes based on the props passed in. This happens before the render() method is called when the component receives new props. The method should return an object for updating or null for not updating anything. It's used in rare cases where the state depends on changes in the props.
class ControlledInput extends React.Component{
constructor(props)
super(props)
this.state={
inputValue: ""
}
//this method is called before the render method is called
static getDerivedStateFromProps(incomingProps,previousState){
//check if the new input value is same as previous state and then update
if(incomingProps.value !== previousState.inputValue){
return{
inputValue: incomingProps.value
};
}
return null;
}
handleInputChange = (event)=>{
this.state({inputValue: event.target,value})
}
render() {
return (
<div>
<input
type="text"
value={this.state.inputValue}
onChange={this.handleInputChange}
/>
</div>
);
}
}
export default ControlledInput;
shouldComponentUpdate(): tThis method is called before getDerivedStateFromProps(). It is a situation where React decides whether to update by returning true or false. If true is returned, then the getDerivedStateFromProps() method is called.
class ToggleBtn extends React.Component{ constructor(props){ super(props) this.state={ isActive: false } } shouldComponentUpdate(nextProps,nextState){ return nextState.isActive } toggleButtonState = ()=> { this.state((prevState)=>({isActive: !prevState.isActive})); }; render(){ const buttonText = this.state.isActive ? 'Deactivate' : 'Activate'; const stateMessage = this.state.isActive ? 'Active' : 'Inactive'; return( <div> <button onClick={this.toggleActive}>{buttonText}</button> <p>{stateMessage} state: {this.props.value}</p> </div> ) } } export default ToggleBtn;
render(): This method generates an updated version of the virtual DOM when shouldComponentmount() returns true.
getSnapshotBeforeUpdate(): Before the virtual DOM is fed into the DOM, the render() method in React allows the framework to capture a snapshot of the previous state and props of a component. This is useful when an action needs to be performed with the previous state and props of the component before any update takes place.
class AnimatingBox extends React.Component { constructor(props) { super(props); this.state = { left: 0, }; } getSnapshotBeforeUpdate(previousProps, previousState) { return this.state.left; } //componentDidMount will have a role to play here see the next example //for updated code } startAnimation = () => { this.setState({ left: 0 }); }; render() { const { left } = this.state; const boxStyle = { width: '100px', height: '100px', backgroundColor: 'orange', position: 'relative', left: `${left}px`, }; return ( <div> <div style={boxStyle}></div> <button onClick={this.startAnimation}>Start Animation</button> </div> ); } } export default AnimatingBox;
componentDidMount(): This is the last execution of the update method before the component unmounts. Once the render method has been called and all changes have been applied to the DOM, the updated props and state will have been re-rendered.
class AnimatingBox extends React.Component {
constructor(props) {
super(props);
this.state = {
left: 0,
};
}
getSnapshotBeforeUpdate(prevProps, prevState) {
return this.state.left;
}
//this is where the componentDidMount is called
componentDidUpdate(prevProps, prevState, snapshot) {
if (snapshot !== prevState.left) {
const moveBox = () => {
if (this.state.left < 300) {
this.setState((prevState) => ({ left: prevState.left + 5 }));
requestAnimationFrame(moveBox);
}
};
requestAnimationFrame(moveBox);
}
}
startAnimation = () => {
this.setState({ left: 0 });
};
render() {
const { left } = this.state;
const boxStyle = {
width: '100px',
height: '100px',
backgroundColor: 'orange',
position: 'relative',
left: `${left}px`,
};
return (
<div>
<div style={boxStyle}></div>
<button onClick={this.startAnimation}>Start Animation</button>
</div>
);
}
}
export default AnimatingBox;
Component Unmounting Phase
During this phase, there is only one method called componentWillUnmount(). This method is invoked before the React component gets removed. Its purpose is to facilitate cleanups, remove event handlers from the DOM, and close any existing connections. By doing so, it ensures that there are no memory leaks.