diff --git a/src/hooks/useTypingEffect.ts b/src/hooks/useTypingEffect.ts index 240e653..2866685 100644 --- a/src/hooks/useTypingEffect.ts +++ b/src/hooks/useTypingEffect.ts @@ -1,4 +1,4 @@ -import { useState, useEffect } from 'react'; +import { useState, useEffect, useMemo } from 'react'; interface UseTypingEffectOptions { words: string[]; @@ -18,38 +18,45 @@ export function useTypingEffect({ const [isDeleting, setIsDeleting] = useState(false); const [isPaused, setIsPaused] = useState(false); + // Stabilize words array to prevent unnecessary effect resets on re-renders + // when the array reference changes but content remains the same. + // eslint-disable-next-line react-hooks/exhaustive-deps + const stableWords = useMemo(() => words, [JSON.stringify(words)]); + useEffect(() => { let timer: ReturnType; - if (isPaused) { - timer = setTimeout(() => { + const currentWord = stableWords[currentWordIndex]; + const isWordDeleted = isDeleting && currentText === ''; + + // If word is fully deleted, move to next word immediately (no timer) + if (!isPaused && isWordDeleted) { + setIsDeleting(false); + setCurrentWordIndex((prev) => (prev + 1) % stableWords.length); + return; + } + + // Determine speed based on state + const speed = isPaused ? pauseDuration : (isDeleting ? deletingSpeed : typingSpeed); + + timer = setTimeout(() => { + if (isPaused) { setIsPaused(false); setIsDeleting(true); - }, pauseDuration); - } else { - const currentWord = words[currentWordIndex]; - const isWordDeleted = isDeleting && currentText === ''; - - if (isWordDeleted) { - setIsDeleting(false); - setCurrentWordIndex((prev) => (prev + 1) % words.length); } else { - const speed = isDeleting ? deletingSpeed : typingSpeed; + // Typing logic + if (isDeleting) { + setCurrentText((prev) => prev.substring(0, prev.length - 1)); + } else { + const nextText = currentWord.substring(0, currentText.length + 1); + setCurrentText(nextText); - timer = setTimeout(() => { - if (isDeleting) { - setCurrentText((prev) => prev.substring(0, prev.length - 1)); - } else { - const nextText = currentWord.substring(0, currentText.length + 1); - setCurrentText(nextText); - - if (nextText === currentWord) { - setIsPaused(true); - } + if (nextText === currentWord) { + setIsPaused(true); } - }, speed); + } } - } + }, speed); return () => clearTimeout(timer); }, [ @@ -57,7 +64,7 @@ export function useTypingEffect({ isDeleting, isPaused, currentWordIndex, - words, + stableWords, typingSpeed, deletingSpeed, pauseDuration,