Refactor useTypingEffect to fix timer leak and optimize re-renders #5

Merged
google-labs-jules[bot] merged 1 commits from fix-typing-effect-timer-leak-7224626563395361239 into main 2026-01-23 09:06:33 +00:00

View File

@@ -1,4 +1,4 @@
import { useState, useEffect } from 'react';
import { useState, useEffect, useMemo } from 'react';
interface UseTypingEffectOptions {
words: string[];
@@ -18,25 +18,33 @@ 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<typeof setTimeout>;
if (isPaused) {
timer = setTimeout(() => {
setIsPaused(false);
setIsDeleting(true);
}, pauseDuration);
} else {
const currentWord = words[currentWordIndex];
const currentWord = stableWords[currentWordIndex];
const isWordDeleted = isDeleting && currentText === '';
if (isWordDeleted) {
// If word is fully deleted, move to next word immediately (no timer)
if (!isPaused && isWordDeleted) {
setIsDeleting(false);
setCurrentWordIndex((prev) => (prev + 1) % words.length);
} else {
const speed = isDeleting ? deletingSpeed : typingSpeed;
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);
} else {
// Typing logic
if (isDeleting) {
setCurrentText((prev) => prev.substring(0, prev.length - 1));
} else {
@@ -47,9 +55,8 @@ export function useTypingEffect({
setIsPaused(true);
}
}
}
}, speed);
}
}
return () => clearTimeout(timer);
}, [
@@ -57,7 +64,7 @@ export function useTypingEffect({
isDeleting,
isPaused,
currentWordIndex,
words,
stableWords,
typingSpeed,
deletingSpeed,
pauseDuration,