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

Next.js中如何正确结合useEffect与setInterval?计数器异常问题

在Next.js中解决useEffect结合setInterval导致计数器加速的问题

问题原因分析

你的代码存在几个核心问题,导致计数器加速和随机递增:

  1. useEffect使用async回调:useEffect的回调函数不能是async类型——async函数返回的是Promise,而effect要求清理函数必须是普通函数,这会导致原有的clearInterval无法被正确执行,旧定时器得不到清理,多个定时器同时运行就会让计数器加速。
  2. 全局变量key:全局变量会在组件多次渲染时被共享修改,导致SWR的请求key频繁变化,触发多次数据请求,进而多次执行useEffect创建新的定时器。
  3. 依赖项不合理:将router作为useEffect的依赖项,router对象的引用可能频繁变化,导致effect重复执行,创建多个定时器。
  4. 未正确导入useRouter:代码中使用了router但没有导入,这会导致运行错误,间接引发状态异常。

修正后的完整代码

import useSWR from "swr";
import { useEffect, useState, useRef } from "react";
import { useRouter } from "next/router";

const fetcher = (...args) => fetch(...args).then((res) => res.json());

export default function App() {
  const router = useRouter();
  const [timer, setTimer] = useState(0);
  const [info, setInfo] = useState({});
  const timerRef = useRef(null);
  const [key, setKey] = useState("");

  // 单独监听路由参数变化,更新请求key
  useEffect(() => {
    if (router.query?.id) {
      setKey(router.query.id);
    }
  }, [router.query]);

  // SWR请求:仅当key存在时发起请求
  const { data, error } = useSWR(key ? `/api/getInfo?key=${key}` : null, fetcher);

  // 管理定时器与数据更新
  useEffect(() => {
    // 创建定时器并保存到ref
    timerRef.current = window.setInterval(() => {
      setTimer((prevTime) => prevTime + 1);
    }, 1000);

    // 处理服务器返回的数据
    if (data) {
      console.log("Data fetched from server>>>>", data);
      setInfo(data.info);
    }

    // 清理函数:确保每次effect执行前清除旧定时器
    return () => {
      if (timerRef.current) {
        window.clearInterval(timerRef.current);
        timerRef.current = null;
      }
    };
  }, [data]);

  return (
    <>
      <p>Counter - {timer} </p>
      <p>Data from Server - {JSON.stringify(info)} </p>
    </>
  );
}

关键修改说明

  • 移除async的useEffect回调:effect回调改为普通函数,内部如需异步操作可单独定义async函数调用。
  • 用组件state替代全局变量key:避免全局状态污染,确保组件内状态独立可控,路由参数变化时通过单独的useEffect更新key。
  • 使用useRef保存定时器ID:解决闭包问题,确保清理函数能访问到最新的定时器ID,彻底清除旧定时器。
  • 拆分useEffect职责:将路由监听、定时器管理、数据请求拆分为独立的逻辑块,避免单一effect承担过多职责导致的重复执行。
  • 修正SWR请求触发条件:仅当key存在时发起请求,避免无效的空请求触发不必要的effect执行。
  • 修复数据显示问题:使用JSON.stringify将info对象转为字符串,避免直接显示对象出现[object Object]的情况。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 02:05:23