feat: optimize Hero component by isolating typing effect state

Extracted the high-frequency typing animation logic into a new, memoized `TypedText` component.
This prevents the entire `Hero` component (including the heavy `GradientBlinds`) from re-rendering on every character update.

- Created `TypedText` component in `Hero.tsx`
- Wrapped `TypedText` in `React.memo`
- Moved `useTypingEffect` call into `TypedText`
- Updated `Hero` to use `TypedText`

Co-authored-by: ragusa-it <196988693+ragusa-it@users.noreply.github.com>
This commit is contained in:
google-labs-jules[bot]
2026-01-28 01:58:55 +00:00
parent 6b8f54072e
commit 669e96a77c
2 changed files with 21 additions and 9 deletions

View File

@@ -1,4 +1,4 @@
import { useState, useEffect, useRef } from "react";
import { useState, useEffect, useRef, memo } from "react";
import { Link } from "react-router-dom";
import { motion } from "motion/react";
import { useTranslation } from "../../i18n";
@@ -9,6 +9,21 @@ import styles from "./Hero.module.css";
const GRADIENT_COLORS = ["#26a269", "#8ff0a4"];
interface TypedTextProps {
words: string[];
}
const TypedText = memo(({ words }: TypedTextProps) => {
const { text } = useTypingEffect({
words,
typingSpeed: 80,
deletingSpeed: 40,
pauseDuration: 2500,
});
return <>{text}</>;
});
export function Hero() {
const { t } = useTranslation();
const [showScrollIndicator, setShowScrollIndicator] = useState(true);
@@ -29,13 +44,6 @@ export function Hero() {
return () => observer.disconnect();
}, []);
const { text } = useTypingEffect({
words: t.hero.rotatingWords,
typingSpeed: 80,
deletingSpeed: 40,
pauseDuration: 2500,
});
return (
<section className={styles.hero}>
<div
@@ -100,7 +108,7 @@ export function Hero() {
>
<span>{t.hero.tagline}</span>
<span className={styles.typed}>
{text}
<TypedText words={t.hero.rotatingWords} />
<span className={styles.cursor}>|</span>
</span>
</motion.div>