skip to Main Content

i have a weird issue with React and the timout function.
For some reason i want a string to be added to a useEffect letter by letter. So i have written this code:

const [placeholder, setPlaceholder] = useState < string > ('')

useEffect(() => {
    const str = "How may I help you today?";
    const letters = Array.from(str);

    const addLetterWithDelay = (index: number) => {
        if (index < letters.length) {
            setTimeout(() => {
                setPlaceholder(prevPlaceholder => prevPlaceholder + letters[index]);
                addLetterWithDelay(index + 1);
            }, 1000); // Delay of 1 second
        }
    };

    addLetterWithDelay(0); // Start adding letters from index 0
}, []);

The problem is that the letter is setting it twice
So the output will be: HHooww mmaayy II hheellpp yyoouu ttooddaayy??
even if i check with a statement if the last char of the placeholder is the same as letters[index] or not, it still prints that it is not the same and go executing

2

Answers


  1. Modify your useEffect to:

     useEffect(() => {
        const str = "How may I help you today?";
        const letters = Array.from(str);
        let timerId: NodeJS.Timeout; // Declare a variable to hold the timeout ID
    
        const addLetterWithDelay = (index: number) => {
            if (index < letters.length) {
                timerId = setTimeout(() => {
                    setPlaceholder(prevPlaceholder => prevPlaceholder + letters[index]);
                    addLetterWithDelay(index + 1);
                }, 1000); // Delay of 1 second
            }
        };
    
        addLetterWithDelay(0); // Start adding letters from index 0
    
        return () => clearTimeout(timerId); // Clear the timeout when the component is unmounted or the useEffect hook re-runs
    }, []);
    

    This manner, if your component re-renders and the useEffect hook is called again, the current timeout is cleared and the addLetterWithDelay method is terminated.

    Login or Signup to reply.
  2. The issue you’re experiencing is due to the way React’s state updates work with the setTimeout function. When you call setPlaceholder inside the setTimeout callback, React will schedule a state update, but the component may have already re-rendered with the previous state before the setTimeout callback is executed. This can lead to unexpected behavior, such as the string being added twice.

    To fix this issue, you can use the functional form of setPlaceholder, which takes the previous state as an argument. This ensures that you’re always updating the state based on the latest value.

    const [placeholder, setPlaceholder] = useState<string>('')
    
    useEffect(() => {
        const str = "How may I help you today?";
        const letters = Array.from(str);
    
        const addLetterWithDelay = (index: number) => {
            if (index < letters.length) {
                setTimeout(() => {
                    setPlaceholder(prevPlaceholder => prevPlaceholder + letters[index]);
                    addLetterWithDelay(index + 1);
                }, 1000); // Delay of 1 second
            }
        };
    
        addLetterWithDelay(0); // Start adding letters from index 0
    }, []);

    By using the functional form of setPlaceholder, you ensure that each update is based on the latest state, preventing the issue of the string being added twice.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search