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

React中弹窗重复弹出问题求助:移除StrictMode后遇ResizeObserver警告

拼图游戏弹窗重复触发与StrictMode移除后的警告问题

我开发了一款拼图游戏,完成拼图后会弹出提示alert,接着弹出确认窗口询问是否继续游玩,但目前这些弹窗会重复出现两次。我尝试移除index.js中的React.StrictMode,却出现了"ResizeObserver loop completed with undelivered notifications."警告,且应用无法维持原有正常运行状态。

App.js 代码

import React, { useState } from "react";
import "./App.css";
import "./puzzle.css";
import { JigsawPuzzle } from "react-jigsaw-puzzle/lib";
import "react-jigsaw-puzzle/lib/jigsaw-puzzle.css";
import catImg from "./cat.jpeg";
import elephantImg from "./elephant.jpg";
import carImg from "./car.jpg";
import kidsImg from "./kids.jpg";
import sheepImg from "./sheep.png";

const puzzleImages = [catImg, elephantImg, carImg, kidsImg, sheepImg];

function App() {
  const [imageIndex, setImageIndex] = useState(getRandomIndex());

  function getRandomIndex() {
    return Math.floor(Math.random() * puzzleImages.length);
  }

  const handlePlayAgain = () => {
    const confirmPlayAgain = window.confirm("Do you want to play another puzzle?");
    if (confirmPlayAgain){
    const newIndex = getRandomIndex();
    setImageIndex(newIndex);
}
else { 
    alert("Thank you for playing")
}
  };

  const handleSolved = () => {
    alert("Good job!");
    handlePlayAgain();
  };

  return (
    <>
      <h2 className="tag">Un-puzzle the pieces</h2>
      <JigsawPuzzle
        imageSrc={puzzleImages[imageIndex]}
        rows={2}
        columns={2}
        onSolved={handleSolved}
        className="jigsaw-puzzle"
      />
    </>
  );
}

export default App;

Index.js 代码

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

reportWebVitals();

问题解决办法

弹窗重复触发的原因

React StrictMode在开发环境下会双重调用组件内的事件回调、状态更新逻辑,目的是检测潜在副作用。handleSolved被调用两次,导致弹窗重复弹出。

解决弹窗重复的方法

不用移除StrictMode,用以下两种方式处理:

方式1:状态标记控制触发次数

给App组件加一个状态,标记是否已经触发过完成逻辑,避免重复执行:

function App() {
  const [imageIndex, setImageIndex] = useState(getRandomIndex());
  const [hasSolved, setHasSolved] = useState(false); // 新增状态

  function getRandomIndex() {
    return Math.floor(Math.random() * puzzleImages.length);
  }

  const handlePlayAgain = () => {
    const confirmPlayAgain = window.confirm("要再来一局吗?");
    if (confirmPlayAgain){
      const newIndex = getRandomIndex();
      setImageIndex(newIndex);
      setHasSolved(false); // 重置标记,允许下一次触发
    } else { 
      alert("感谢游玩!")
    }
  };

  const handleSolved = () => {
    if (!hasSolved) {
      setHasSolved(true);
      alert("太棒了!");
      handlePlayAgain();
    }
  };

  // 其余代码不变
}

方式2:防抖函数限制执行频率

用防抖函数让handleSolved在短时间内只执行一次:

// 先实现一个简单的防抖函数
const debounce = (func, delay) => {
  let timer;
  return (...args) => {
    clearTimeout(timer);
    timer = setTimeout(() => func(...args), delay);
  };
};

function App() {
  // 其余状态不变

  // 给handleSolved加防抖
  const handleSolved = debounce(() => {
    alert("太棒了!");
    handlePlayAgain();
  }, 100);

  // 其余代码不变
}

移除StrictMode后的ResizeObserver警告处理

这个警告来自react-jigsaw-puzzle库的内部实现,不影响功能,可通过以下方式消除:
在index.js最顶部添加代码,过滤掉无效的ResizeObserver通知:

const originalRO = window.ResizeObserver;
window.ResizeObserver = class extends originalRO {
  constructor(callback) {
    super((entries, observer) => {
      entries = entries.filter(entry => entry.target.isConnected);
      callback(entries, observer);
    });
  }
};

// 原index.js代码...

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 09:54:55