You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何Next.js添加状态判断会触发Rendered more hooks错误?

问题原因:"Rendered more hooks than during the previous render"错误解析

问题场景

你编写的Next.js客户端时间统计组件,在保留开头两个if状态检查时触发上述错误,移除后错误消失,核心原因是违反了React Hook的调用规则。

错误根源

React对Hook的调用有严格要求:组件每次渲染时,Hook的调用顺序必须完全一致,不能在条件分支、循环或提前返回的逻辑之后调用Hook。

结合你的代码来看:

  • 当组件处于loading状态,或者没有session时,代码会通过if语句提前返回JSX,导致后续的useState和useEffect两个Hook根本不会执行。
  • 当status从loading变为authenticated时,组件重新渲染,此时会执行所有Hook,Hook的调用数量比上一次渲染(loading阶段)多,React检测到这个不一致,就抛出了错误。

修复方案

把所有Hook调用移到组件的最顶部,确保每次渲染都按相同顺序执行所有Hook,再把条件判断放在Hook之后:

'use client';

import React, { useEffect, useState } from 'react';
import { useSession } from 'next-auth/react';

const TimeTracking: React.FC = () => {
  // 所有Hook必须放在条件判断前,保证每次渲染调用顺序一致
  const { data: session, status } = useSession();
  const [timeSpent, setTimeSpent] = useState<number>(0);

  const saveToLocalStorage = (value: number) => {
    if (typeof window !== 'undefined') {
      const todayDateString = new Date().toLocaleDateString();
      localStorage.setItem('date', todayDateString);
      localStorage.setItem('timeSpent', value.toString());
    }
  };

  useEffect(() => {
    let initialTimeSpent = 0;
    const todayDateString = new Date().toLocaleDateString();

    if (typeof window !== 'undefined' && session) {
      if (localStorage.getItem('date') === todayDateString) {
        initialTimeSpent = parseInt(localStorage.getItem('timeSpent') || '0');
      }
      setTimeSpent(initialTimeSpent);

      const updateTimeSpent = () => {
        setTimeSpent((prevTimeSpent) => {
          const updatedTimeSpent = prevTimeSpent + 1;
          saveToLocalStorage(updatedTimeSpent);
          return updatedTimeSpent;
        });
      };

      const timer = setInterval(updateTimeSpent, 1000);

      const handleBeforeUnload = (e: BeforeUnloadEvent) => {
        const todayDateString = new Date().toLocaleDateString();
        const timetracker = {
          timeSpent: localStorage.getItem('timeSpent'),
          date: todayDateString,
        };
        const requestBody = JSON.stringify({ timetracker });
        navigator.sendBeacon(`/api/user/${session?.user?._id}`, requestBody);
      };

      window.addEventListener('beforeunload', handleBeforeUnload);
      return () => {
        clearInterval(timer);
        window.removeEventListener('beforeunload', handleBeforeUnload);
      };
    }
  }, [session]);

  // 条件判断放在所有Hook调用之后
  if (status === 'loading') {
    return <div>Loading...</div>;
  }

  if (!session) {
    return <div>No session data</div>;
  }

  return (
    <div>
      <h3>Total Time Spent: {timeSpent} minutes</h3>
      <p>Tracking time spent in the app...</p>
    </div>
  );
};

export default TimeTracking;

内容的提问来源于stack exchange,提问作者in43sh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 14:36:07