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

如何避免React中useEffect内router.push引发的无限循环?

解决React中因状态数组更新导致的路由push无限循环问题

问题根源

你当前的代码里,useEffect依赖了整个users数组——每次添加用户时都会生成新的数组引用,触发useEffect执行push修改URL。而push操作可能触发组件重新渲染,此时users的新数组引用又会再次触发useEffect,形成无限循环。实际上你只需要监听用户数量的变化,而非整个数组的引用变化。


方案1:修改useEffect依赖为用户数量

将useEffect的依赖从users改为users.length,length是基本类型,不会因为数组引用变化触发不必要的副作用,只有数量真的改变时才更新URL:

export default function Home() {
  const {push} = useRouter();
  const [users, setUsers] = useState<string[]>([]);

  const addUser = useCallback(() => {
    setUsers([...users, `Tommy-${Math.random()}`]);
  }, [users]);

  useEffect(() => {
    push({
      pathname: "/",
      query: {
        amount: users.length,
      },
    });
  }, [users.length, push]); // 仅监听用户数量变化

  return (
    <>
      <div>
        <button onClick={addUser}>Add user</button>
        <ul>
          {users.map((user) => (
            <li key={user}>{user}</li>
          ))}
        </ul>
      </div>
    </>
  );
}

方案2:优化状态更新逻辑(更优)

使用useState的函数式更新修改users,让addUser不需要依赖users,避免每次用户变化时生成新的函数引用,同时保持监听用户数量:

export default function Home() {
  const {push} = useRouter();
  const [users, setUsers] = useState<string[]>([]);

  // 函数式更新,无需依赖users
  const addUser = useCallback(() => {
    setUsers(prevUsers => [...prevUsers, `Tommy-${Math.random()}`]);
  }, []);

  useEffect(() => {
    push({
      pathname: "/",
      query: {
        amount: users.length,
      },
    });
  }, [users.length, push]);

  return (
    <>
      <div>
        <button onClick={addUser}>Add user</button>
        <ul>
          {users.map((user) => (
            <li key={user}>{user}</li>
          ))}
        </ul>
      </div>
    </>
  );
}

方案3:增加URL状态判断(可选)

为了避免重复执行push(比如URL的amount已经和当前用户数量一致时),可以先判断当前URL参数,再决定是否更新:

import { useRouter } from 'next/router';
import { useState, useCallback, useEffect } from 'react';

export default function Home() {
  const router = useRouter();
  const {push} = router;
  const [users, setUsers] = useState<string[]>([]);

  const addUser = useCallback(() => {
    setUsers(prevUsers => [...prevUsers, `Tommy-${Math.random()}`]);
  }, []);

  useEffect(() => {
    const currentAmount = router.query.amount;
    // 仅当URL参数与当前用户数量不一致时才更新
    if (currentAmount !== String(users.length)) {
      push({
        pathname: "/",
        query: {
          amount: users.length,
        },
      });
    }
  }, [users.length, push, router.query.amount]);

  return (
    <>
      <div>
        <button onClick={addUser}>Add user</button>
        <ul>
          {users.map((user) => (
            <li key={user}>{user}</li>
          ))}
        </ul>
      </div>
    </>
  );
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 18:00:40