Sometimes we need to make decisions or calculations based on the previous state value of a state variable. For example, I want to call a particular API based on the value of the state variable color. It only takes a simple if statement.
componentDidUpdate() {
if(this.state.color === "blue"){
console.log("Loading blue api!!!")
}
}
But what if I want to load the
To solve this problem, React Js passes the previous state and the previous props to the
componentDidUpdate(prevProps: Props, prevState: State) {
if(prevState.color === "green" && this.state.color === "blue"){
console.log("Loading Green to Blue!!!")
}
}
Below is the complete class component to demonstrate how to access the previous state in React lifecycle methods.
import { Component } from "react";
interface Props {}
interface State {
color: string
}
export default class App extends Component{
constructor(props: Props) {
super(props)
this.state = {color: "white"};
this.changeColor = this.changeColor.bind(this)
}
componentDidUpdate(prevProps: Props, prevState: State) {
if(prevState.color === "green" && this.state.color === "blue"){
console.log("Loading Green to Blue!!!")
}
}
changeColor(color: string) {
this.setState({color: color})
}
render(){
return <>
<div style={{backgroundColor: this.state.color}}>Color</div>
<button
style={{backgroundColor: "red", color: "white"}}
onClick={() => this.changeColor("red")}>
Update to Red
</button>
<button
style={{backgroundColor: "green", color: "white"}}
onClick={() => this.changeColor("green")}>
Update to Green
</button>
<button
style={{backgroundColor: "blue", color: "white"}}
onClick={() => this.changeColor("blue")}>
Update to Blue
</button>
<button
style={{backgroundColor: "yellow", color: "white"}}
onClick={() => this.changeColor("yellow")}>
Update to Yellow
</button>
</>
}
}
Unlike class components, functional components do not provide an out-of-the-box solution to access the previous value of a state variable in lifecycle hooks. Therefore, I must implement a solution to preserve the previous state value. Below is one way to do it.
const usePrevious = (color: string) => {
const prev = useRef<string>()
useEffect(() => {
prev.current = color
}, [color])
return prev.current
}
That will return my previous state value each time I call it in each component re-render. Here is a complete example of how to use it.
import { useEffect, useRef, useState } from "react"
export const FunctionalComponent = () =>{
const [color, setColor] = useState("green")
const prevColor = usePrevious(color)
useEffect(() => {
if(prevColor === "green" && color === "blue"){
console.log("Loading Green to Blue!!!")
}
})
const changeColor = (color: string) => {
setColor(color)
}
return(<>
<div style={{backgroundColor: color}}>Color</div>
<button
style={{backgroundColor: "red", color: "white"}}
onClick={() => changeColor("red")}>
Update to Red
</button>
<button
style={{backgroundColor: "green", color: "white"}}
onClick={() => changeColor("green")}>
Update to Green
</button>
<button
style={{backgroundColor: "blue", color: "white"}}
onClick={() => changeColor("blue")}>
Update to Blue
</button>
<button
style={{backgroundColor: "yellow", color: "white"}}
onClick={() => changeColor("yellow")}>
Update to Yellow
</button>
</>)
}
const usePrevious = (color: string) => {
const prev = useRef<string>()
useEffect(() => {
prev.current = color
}, [color])
return prev.current
}