2

I started studying reaction hooks. But I have some doubts. I thought I understood, but the empirical evidence shows unexpected behavior, at least as far as I believe I know.

To illustrate my perplexities or misunderstandings, I take the classic exercise that implements a simple clock as an example. Below is the code that implements the functional component.

import {useState, useEffect} from 'react';
 
const Clock = (props) => {
 
    const {show, country, timezone} = props;
    const t = Date.now () + 3600 * timezone * 1000;
    const dateInitial = new date (t);
    const [datE, setDate] = useState (dateInitial);
 
    useEffect (() => {
        const interval = setInterval (() => {
            const t = date.getTime () + (1 * 1000);
            setDate (new date (t));
        }, 1000);
        return () => {
            // ONLY clears the return of this function
            // When the component is unmounted from the DOM
           console.log ("Cleanup function (componentWillUnmount ())");
           clearTimeout (interval); // The setTimeout is cleared as soon as the component is unmounted from the DOM
        }
    }, [date);
 
    return (
        <h2 style = {{display: show? true: 'none'}}> Today in {country} is {date.toLocaleDateString () + '' + date.toLocaleTimeString ()} </h2>
    )
};
 
export default Clock;

The functional component uses useEffect hooked to the "date" state property.

The function:

() => {
            const t = date.getTime () + (1 * 1000);
            setDate (new date (t));
        }, 1000);

Passed as the first parameter to useEffect, it should be used for componentDidMount and componentDidUpdate life cycle events.

While the cleanup function:

return () => {
            // ONLY clears the return of this function
            // When the component is unmounted from the DOM
           console.log ("Cleanup function (componentWillUnmount ())");
           clearTimeout (interval); // The setTimeout is cleared as soon as the component is unmounted from the DOM
        }

it should be executed at the componentWillUnmount event of the component lifecycle.

But if I "run" our component, I see this in the logs:

enter image description here

As you can see, the componentWillUnmount event occurred every second. If I'm not wrong, shouldn't the componentWillUnmount happen when the component is removed from the DOM? In this circumstance, we only have a new rendering of the DOM and not the removal of the element from the DOM. I am perplexed. On the other hand, if you try the following example with the class component:

Clock with class component (on codepen.io)

You will see that console.log ("componentWillUnmount"); never appears ...

I also observe that the component that I inserted in the post loses several seconds if I change the tab, while with the one on codepen.io it does not lose a "beat".

Excuse me, I'm a little confused.

I thank you in advance for your always precious clarifications.

3
  • 1
    The line where you have used useState hook, you have written 'data' instead of date. Commented Nov 21, 2021 at 10:40
  • @varisha15 thank you. It's my error writing the post. In real code is [data]. Thank you again! Commented Nov 21, 2021 at 10:55
  • "thank you" is not needed just click the upward array if you found my comment useful. Commented Nov 21, 2021 at 10:58

1 Answer 1

2

useEffect represent componentDidMount and componentWillUnmount only if you give it an empty dependency array:

useEffect(() => {
    //code that will only be executed when component mount
    return () => {
        //code that will only executed when component unmount
    }
}, [])

In your example, you have date in the dependency array, this mean, every-time date changes, a new execution, think about it like that useEffect is a mini component which it's life depends on the date value every-time date changes it unmout and remount.

The reason we need the return function in such case, is when we have for example a listener that depend on the date value, so each time the date chnage we need to remove the old listener with old value and attach new listener with new value.

useEffect(() => {
    //We attach a listener which depends on date value
    const listenerHandler = () => {console.log(date)}
    window.addEventListener('event', listenerHandler)

    return () => {
       //We need to remove the listener with old value so we don't have many listeners attached each time date changes
       window.removeEventListener('event', listenerHandler)
    }
}, [date])
Sign up to request clarification or add additional context in comments.

4 Comments

Thanks a lot @Abdellah Sabiri for your reply. So, in my case, do you confirm me that it's right that component will be unmount? Doesn't make such behavior functional component less performant than a class component? Because in example posted in codepen.io the component doesn't go through the componentWillUnmount event? Thank you so much for your kind reply.
In your case your component only rerender, it won't unmount, if you want to test the unmout you can add new useEffect with empty dependency array like on the first code example in my answer, you can try to add a console log on it's return function, you will see it wont be executed.
Sorry, I do not understand. Is the cleanup function equivalent to the componentWillUnmount event that occurs in class components? Perhaps it means that the function return in useEffect assumes two different meanings? 1) If the dependency array is empty, it will be executed when unmount occurs (for example, 'changing page application'). 2) If the dependency array is not-empty, a return function will be executed for each re-rendering How could I simulate and intercept unmount of a functional component and the passing to return function of the useEffect in case of an empty array? Thanks
The cleanup function is not equivalent to componentWillUnmount, it just clean when the useEffect get updated. We say it is equivalent to componentWillUnmount when useEffect has no dependency, so useEffect execute once the component mount and cleans once component unmount

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.