perf: deterministik dekor memo'ları ve küçük render süpürmeleri (Faz 7)
Some checks failed
Deploy / deploy (push) Has been cancelled

- pixel-decor: PixelField/PixelDivider piksel üretimi useMemo([seed]) —
  504 iterasyon + ~150 element çekmece reorder'ının her karesinde
  yeniden üretiliyordu
- rapor-listesi: acikSira effect'i önceki-prop desenine döndü (çift render
  ve eslint-disable kalktı), Set lazy init, tekIl useMemo
- program-tablosu: 3 dilimin spread'i useMemo
- typing-animation: displayedText state yerine türetme; kaynak reset'i
  render sırasında — tick başına state yazımı ve effect bağımlılığı azaldı
- site-top-banner: saniyelik geri sayım tiki startTransition'da
- program-liste-verileri: sparkline 6 dizi geçişi tek döngüde
- secimlerim-paneli: SecimSatiri profili prop'tan alır + memo (24 ayrı
  store aboneliği kalktı)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
bilalgursen
2026-08-08 14:29:14 +03:00
parent f3d8bf9b94
commit 78d7c51a7a
7 changed files with 129 additions and 86 deletions

View File

@@ -81,7 +81,6 @@ export function TypingAnimation({
Component
] as TypingAnimationMotionComponent
const [displayedText, setDisplayedText] = useState<string>("")
const [currentWordIndex, setCurrentWordIndex] = useState(0)
const [currentCharIndex, setCurrentCharIndex] = useState(0)
const [phase, setPhase] = useState<"typing" | "pause" | "deleting">("typing")
@@ -109,21 +108,32 @@ export function TypingAnimation({
[words, children]
)
// Kaynak metin değişince animasyon baştan başlar — bilinçli reset
useEffect(() => {
// eslint-disable-next-line react-hooks/set-state-in-effect
setDisplayedText("")
// Kaynak metin değişince animasyon baştan başlar — önceki-prop deseniyle
// render sırasında (effect'te setState çift render yaratıyordu)
const [oncekiKaynak, setOncekiKaynak] = useState(animationSourceKey)
if (animationSourceKey !== oncekiKaynak) {
setOncekiKaynak(animationSourceKey)
setCurrentWordIndex(0)
setCurrentCharIndex(0)
setPhase("typing")
}, [animationSourceKey])
}
// Görünen metin state değil türetme: tick başına ekstra state yazımı ve
// grapheme dizisi allocation'ı kalkar (rerender-derived-state-no-effect)
const displayedText = useMemo(
() =>
Array.from(wordsToAnimate[currentWordIndex] || "")
.slice(0, currentCharIndex)
.join(""),
[wordsToAnimate, currentWordIndex, currentCharIndex]
)
useEffect(() => {
let timeout: ReturnType<typeof setTimeout> | null = null
if (!azMotion && shouldStart && wordsToAnimate.length > 0) {
const timeoutDelay =
delay > 0 && displayedText === ""
delay > 0 && currentCharIndex === 0
? delay
: phase === "typing"
? typingSpeed
@@ -138,9 +148,6 @@ export function TypingAnimation({
switch (phase) {
case "typing":
if (currentCharIndex < graphemes.length) {
setDisplayedText(
graphemes.slice(0, currentCharIndex + 1).join("")
)
setCurrentCharIndex(currentCharIndex + 1)
} else {
if (hasMultipleWords || loop) {
@@ -159,9 +166,6 @@ export function TypingAnimation({
case "deleting":
if (currentCharIndex > 0) {
setDisplayedText(
graphemes.slice(0, currentCharIndex - 1).join("")
)
setCurrentCharIndex(currentCharIndex - 1)
} else {
const nextIndex = (currentWordIndex + 1) % wordsToAnimate.length
@@ -184,7 +188,6 @@ export function TypingAnimation({
phase,
currentCharIndex,
currentWordIndex,
displayedText,
wordsToAnimate,
hasMultipleWords,
loop,