Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Event

What’s executed in order shown

Initial loading of the component

Notice that both these useEffects() witht with the lambda and empty array are called once and only once

console.log("Executing FCDisplayTimeInSameSpot()");

Code Block
    // This useEffect will only run once when the component is first mounted
    useEffect(()=>{
        setInterval(()=>{
            setContainerState(getTheTime());
        }, 10000);
    }, [])

    // This useEffect will only run once when the component is first mounted
    useEffect(() =>{
        console.log("mounting the FCDisplayTimeInSameSpot");
    }, []);

Component needs to be re-rendered

Notice that the component method is first called, then it is unmounted, then is finally re-rendered through the component return() block (you can see this because the useEffect() with only the lambda is called

console.log("Executing FCDisplayTimeInSameSpot()");

Code Block
    // This useEffect will run every time the component is unmounted
    useEffect(() =>{
        return ()=>console.log("unmounting the FCDisplayTimeInSameSpot");
    });
Code Block
   // This useEffect will run every time the component re-renders
    useEffect(() =>{
        console.log(getDisplayData())
    })

...

If you want data to persist across component renders, you need to use useRef(). We'll cover this in another section

All of the above explains why the following code will not run as expected if you don’t use the useRef() callack

Code Block
languagejs
import React, { useState } from 'react'
import { useEffect } from 'react';
import { useRef } from 'react';

function getTheTime()
{
    let currentDate = new Date();
    let currentTime = currentDate.getHours() + ":" + currentDate.getMinutes() + ":" + currentDate.getSeconds();
    return currentTime;
}

export default function ContainerFcWuE(){
    const [simpleField, setSimpleField] = useState('');
    const [containerState, setContainerState] = useState([getTheTime()]);
    /* Without these two lines below, this code will not work as expected
     * The problem is, every time a state field changes the function is
     * is re-executed in it's entirety, so the state fields are completely
     * reset.  I know I was suprised by this fact!
     * 
     * useRef allows you to create a mutable value that does not cause a 
     * re-render when it is changed.
     * 
     * If you remove containerRef and containerRef.current and replace
     * containerRef.current with containerState, you will see the problem.
     * 
     * A description of this problem and a solution can be found at
     * https://stackoverflow.com/questions/56511176/state-being-reset
     */
    const containerRef = useRef([]);
    containerRef.current = containerState;
    const addToList = name => {
       console.log(`Current array: ${containerRef.current}`);
        const update = [...containerRef.current, name];

       console.log(`Updated array: ${update}`);
  
        setContainerState(update);
    }
  
    const addTimeToList = () => {
        addToList(getTheTime())
    };

    const getDisplayData = () => {
        const cdata = containerState.map((item, index) =>
                                    <li key={index}>{item}</li>);
        return cdata;
    }

    // This useEffect will only run once when the compone is mounted
    useEffect(()=>{
        setInterval(()=>{
            addTimeToList()
        }, 10000);
    }, [])

    // This useEffect will run every time the component re-renders
    useEffect(() =>{
        console.log(getDisplayData())
    })

    // This useEffect will run every time the simpleField changes
    useEffect(() =>{
        console.log(simpleField);
    }, [simpleField]);

    // This useEffect will run every time the component is unmounted
    useEffect(() =>{
        return ()=>console.log("unmounting the ContainerFcWuE");
    });

    return (
        <>
            Type something (open dev tools/console to see behaviour)<input type='text' value={simpleField} onChange={(e) => setSimpleField(e.target.value)} />
            <div onClick={e => setSimpleField("YYY")}>
                <h2>[fcwue] Click Me</h2>
            </div>
            <ul>{getDisplayData()}</ul>
        </>
    )
}