Avatar

CaiCai

INITIALIZING SYSTEM

封面

PhotoWall 加载完成后闪一下 — 修复总结

2026-06-29 13:14:32
# bug修复
✨ 心情:激动
👁 次阅读

现象

点击导航栏切换到"照片墙"页面,内容加载动画播完之后,整个组件闪一下(瞬间透明缩小再恢复),然后才正常显示。

真凶:useEffect 把首次加载当成了搜索过渡

⚠ 根因: useEffect 监听了 searchQuery,页面首次挂载时 searchQuery''(空字符串),effect 照常触发,把内容设成 opacity-0 scale-95,250ms 后再恢复。
这个 effect 是为"搜索时切换结果"设计的,但写的人没有排除首次加载的情况。

改前代码

useEffect(() => {
  setIsTransitioning(true);  // ← 页面一加载就藏内容

  const timer = setTimeout(() => {
    setActiveQuery(searchQuery.toLowerCase());
    setIsTransitioning(false); // ← 250ms 后才恢复
  }, 250);

  return () => clearTimeout(timer);
}, [searchQuery]);

加载时序

页面内容渲染完成
  ↓
useEffect 触发 (searchQuery = '')
  ↓
setIsTransitioning(true)
  ↓
内容变为 opacity-0 + scale-95   ← 看不见了!
  ↓
250ms 后
  ↓
setIsTransitioning(false)
  ↓
内容恢复 opacity-100 + scale-100  ← 闪回来了!

改后代码

useEffect(() => {
  if (!searchQuery) {          // ← 空查询:跳过过渡
    setActiveQuery('');
    setIsTransitioning(false);
    return;
  }
  setIsTransitioning(true);    // ← 只有真正搜索时才过渡
  const timer = setTimeout(() => {
    setActiveQuery(searchQuery.toLowerCase());
    setIsTransitioning(false);
  }, 250);
  return () => clearTimeout(timer);
}, [searchQuery]);

顺便修的两个问题

改动 2:去掉双层动画

外层 PageTransition 已经在做 CSS y:20→0 上滑动画。照片墙内部还有一层 AnimatePresence + motion.div 也在做 y:20→0。两层叠加:

  • 视觉起始点变成 y:40(20 + 20)
  • 两个动画时长不同(0.35s vs 0.4s),不同步
  • 退出动画时 framer-motion 操作 DOM 可能产生空帧

**方案:**删掉内层 AnimatePresence + motion.div,只保留外层 PageTransition。

改动 3:简化照片加载

PhotoImg 组件有骨架占位、加载失败状态、loading="lazy"opacity 0→100 过渡。每个相册就一张封面图,这些花活没必要,去掉更干净。

经验

📌 "加载完成后闪一下" 这种 bug,说明不是加载过程的问题,是加载完后代码主动做了什么事。排查方向:搜首次挂载时会触发的 useEffectsetTimeoutAnimatePresence 退出回调。