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

React报错:Maximum update depth exceeded问题求助(附代码)

解决React中'Maximum update depth exceeded'错误(Socket.io通信场景)

问题根源

你遇到的无限循环更新问题,核心原因是第二个useEffect的依赖配置错误:

  • 该useEffect依赖UIoutputs,每次UIoutputs状态更新时,都会重新执行钩子并给Socket注册新的UIoutputs事件监听器。
  • 当服务器推送数据时,监听器触发setUIoutputs更新状态,状态变化又会再次触发useEffect执行,形成无限循环,最终触发更新深度超限错误。
  • 重复注册的监听器还会导致同一数据多次触发状态更新,进一步加剧问题。

修复后的代码

const address = "http://localhost:4010"
const socket = io(address);

function App() {

  const [MenuState, setMenuState] = useState("/")

  const [UIinputs, setUIinputs] = useState({
    progressState: "stop"
  });

  const [UIoutputs, setUIoutputs] = useState({
    deliveredEnergy: 0,
    estTime: "00:00:00",
    estCost: 0,
    soc: 75,
    chargerState: 4,
    currentPower: 0,
    progressState: 2,
    current: 0,
    voltage: 5,
    carID: "a",
    debug: [{}, {}]
  });

  useEffect(() => {
    socket.emit('UIinputs', UIinputs)
  }, [UIinputs])

  useEffect(() => {
    // 独立定义事件处理函数,方便后续移除监听
    const handleUIOutputs = (data) => {
      setUIoutputs(prevState => ({
        ...prevState,
        deliveredEnergy: data.deliveredEnergy,
        estTime: data.estTime,
        soc: data.soc,
        chargerState: data.chargerState,
        currentPower: data.currentPower,
        progressState: data.progressState,
        current: data.current,
        carID: data.carID,
        voltage: data.voltage,
        debug: data.debug,
      }));
    };

    // 仅在组件挂载时注册一次事件监听
    socket.on('UIoutputs', handleUIOutputs);

    // 组件卸载时移除监听,避免内存泄漏
    return () => {
      socket.off('UIoutputs', handleUIOutputs);
    };
  }, []) // 空依赖数组,确保钩子只执行一次

  return (
    <React.Fragment>
      <CssBaseline />
      <div className='app-container'>
        <div className='top-bar'>
          <Header />
          <BackButton
            MenuState={MenuState}
            setMenuState={setMenuState} />
          <ScanQR />
        </div>
        <Routes>
          <Route path='/' element={
            <Menu
              UIoutputs={UIoutputs}
              setMenuState={setMenuState} />}>
          </Route>
          <Route path='/profile' element={
            <Profile
              UIoutputs={UIoutputs} />}>
          </Route>
          <Route path="/station" element={
            <Charger
              UIinputs={UIinputs}
              setUIinputs={setUIinputs}
              UIoutputs={UIoutputs}
              setUIoutputs={setUIoutputs} />}>
          </Route>
          <Route path="/dev" element={
            <Dev
              UIoutputs={UIoutputs} />}>
          </Route>
        </Routes>
        <BottomBar />
      </div>
    </React.Fragment>
  );
};

关键修改说明

  1. 移除不必要的依赖:第二个useEffect使用空依赖数组[],确保事件监听只在组件挂载时注册一次,不会重复绑定。
  2. 函数式状态更新:使用setUIoutputs(prevState => ...)的形式更新状态,无需依赖当前UIoutputs值,避免了依赖项的冗余添加。
  3. 清理事件监听:添加返回函数在组件卸载时移除Socket事件监听,防止内存泄漏。

内容的提问来源于stack exchange,提问作者Alperen Yılma

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 10:03:20