今天修复了网站主题切换按钮的一个重要问题。这个问题困扰了我一段时间,主要表现为页面加载时主题切换按钮不显示图标,只有在点击后才会出现。

问题分析

问题的根源在于 Next.js 的客户端组件水合(Hydration)过程:

  1. 最初的实现在水合完成前返回 null
  2. 过度依赖 useTheme hook 的返回值
  3. 动画状态的控制时机不当

解决方案

最终通过以下方式解决:

  1. 分离静态渲染和动态渲染

    • 在未水合时使用静态图标
    • 水合完成后使用动画图标
  2. 直接从 DOM 读取初始主题

    1
    2
    3
    const initialTheme = document.documentElement.classList.contains('dark') 
    ? 'dark'
    : 'light'
  3. 为动画组件设置正确的初始状态

    1
    initial={theme === "light" ? "sun" : "hidden"}

经验教训

  1. 处理 SSR 和客户端水合时,需要特别注意初始渲染状态
  2. 不要过度依赖客户端状态,可以直接读取 DOM 获取初始信息
  3. 在添加动画效果前,确保基础功能正常工作
  4. 分离静态和动态渲染可以提供更好的用户体验

这次的修复让我对 Next.js 的 SSR 和客户端水合有了更深的理解。在处理类似问题时,应该先确保基础功能正常,再逐步添加动画等增强功能。