React: useEffect and componentDidMount

Ifeoluwa Akinremi Wade
4 min readJan 30, 2022
Photo by Lautaro Andreani on Unsplash

As I am sharpening my React skills, I will be documenting what I have learned. At the moment I am learning how to use React hooks. My journey into React involved a lot of classes and their lifecycles. Now I’m upgrading my skills with modern React.

I just finished learning how to use the useEffect hook. The way I confirm if I have grasped what I’ve learned about hooks is by seeing if I can compare one to a React class lifecycle. Now, I don’t know if every hook is comparable to a class lifecycle (I haven’t skimmed ahead), but so far they have been. I found that useEffect is similar to componentDidMount. They both require for the component to have been rendered onto the DOM. The hook useEffect runs on every render; whereas, the method componentDidMount, needs the component to have been rendered onto the DOM in order to be called — hence component did mount. They both are great for fetching data and timers.

Inside componentDidMount

Here is an example of componentDidMount fetching data in a class component using props that were passed from Redux Actions using Javascript Fetch— via Redux global store(a whole other situation), that are fetching from a database.

Fetching In componentDidMount

class App extends Component {  
componentDidMount() {
this.props.fetchDaycares()
this.props.fetchToddlers()
}
render () {
return (...)
}
}

As we already know, the method componentDidMount needs the component to be already mounted onto the DOM to be called. So, for the fetch above to begin, all of App component needs to be mounted onto the DOM — all that is to be rendered of course.

Timer In componentDidMount

Thanks to the official React documentation, here is a timer in componentDidMount

class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}

componentDidMount() {
this.timerID = setInterval(
() => this.tick(),
1000
);
}

componentWillUnmount() {
clearInterval(this.timerID);
}

tick() {
this.setState({
date: new Date()
});
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}

Upon mounting, the first method called is the constructor, that is initializing the local state, which is date: new Date() . Next, the render method has rendered this.state.date.toLocaleTimeString() (clock) onto the DOM. Once the whole component has mounted the DOM, componentDidMount will be called and the timer on the clock will begin. The function, setInterval, is repeatedly calling the function tick every second; therefore, causing the clock to increase every second. Inside tick, the state is being updated causing a re-render of the clock in the DOM.

Inside useEffect

useEffect hooks allow for side effects in your component, basically. The side effects are: fetching data, timers, etc.

Fetching In useEffect

A big thank you to Robin Wieruch for providing this fetching useEffect

const [data, setData] = useState({ hits: [] });useEffect(() => {
const fetchData = async () => {
const result = await axios(
'https://hn.algolia.com/api/v1/search?query=redux',
);
setData(result.data);
}
fetchData();
}, []);

In the code above, we see that there is an async function, fetchData, that is fetching from an API with axios. The data fetched will set into the local state. Because we are setting the state with every data fetch, useEffect runs a fetch on a loop. useEffect runs when the components mounts, but also with every update in the component. The empty array added as a second argument, provides the condition that a fetch should only happen when the component mounts. If the desire was that a fetch should take place when the data changes, then the variable data would be placed within the array brackets. Because useEffect creates side effects, adding the empty array, or state variable as the second variable is what would trigger the side effect.

Timer in useEffect

const Timer = () => {
const [count, setCount] = useState(100)
useEffect(() => {
setTimeout(() => {
setCount((count) => count - 5);
}, 1000)
if(count <= 0){
setCount(0)
}
})
...
}

Above I built a timer that counts down by five from 100. I initialized and set the local state to 100. After the component mounts (after a browser refresh), useEffect runs and the timer begins. Like it should, the timer continues to count down by five, even past zero. So I added a conditional that keeps the timer at zero, once the count hits zero. Now I didn’t build a clock with a timer, but compared to the timer built using class lifecycles above, this is really lean.

--

--