diff --git a/.jules/bolt.md b/.jules/bolt.md index a7efe75..8242db8 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -1,3 +1,7 @@ ## 2024-05-22 - Missing Scripts and Environment **Learning:** The project lacks `lint` script in `package.json`. Running `pnpm lint` might invoke system tools (like Android Lint?) instead of failing or doing nothing useful. Always check `package.json` scripts first. **Action:** Use specific commands like `pnpm exec tsc --noEmit` or `npx vitest` as discovered/documented, rather than assuming standard scripts exist. + +## 2024-05-22 - High-Frequency State Isolation +**Learning:** High-frequency state updates (like typing effects) in large parent components (`Hero`) trigger massive unnecessary re-renders of expensive sub-trees (`GradientBlinds`, `Button`). +**Action:** Isolate high-frequency state into small, leaf-node components (e.g., `TypedText`) and wrap them in `React.memo` if necessary, keeping the heavy parent static. diff --git a/src/components/sections/Hero.tsx b/src/components/sections/Hero.tsx index b2c0d21..e9ef169 100644 --- a/src/components/sections/Hero.tsx +++ b/src/components/sections/Hero.tsx @@ -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 (
{t.hero.tagline} - {text} + |