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

React中触发setTimeout:游戏获胜后延迟重置状态

解决React Tic-Tac-Toe获胜后延迟3秒重置状态的问题

嘿,我完全懂你的需求!你不需要在组件挂载时就触发延迟重置,只需要在calculateWinner检测到获胜的那一刻启动定时器就好。咱们直接把定时器逻辑嵌在获胜判定的流程里就行,下面结合tic-tac-toe的示例给你具体实现方案:

核心思路

  1. 先写一个专门的resetGame函数,用来把游戏状态(棋盘、当前玩家等)恢复到初始值
  2. 在处理落子的函数中,每次落子后调用calculateWinner检查是否产生赢家
  3. 一旦检测到赢家,就用setTimeout延迟3秒调用resetGame
  4. 记得清理定时器,避免组件卸载后定时器还在执行导致内存泄漏

具体代码实现(函数组件版本)

import { useState, useRef, useEffect } from 'react';

function TicTacToe() {
  const [board, setBoard] = useState(Array(9).fill(null));
  const [currentPlayer, setCurrentPlayer] = useState('X');
  // 用useRef保存定时器ID,方便后续清除
  const timeoutId = useRef(null);

  // 重置游戏状态的函数
  const resetGame = () => {
    setBoard(Array(9).fill(null));
    setCurrentPlayer('X');
  };

  // 组件卸载时清除未执行的定时器,防止内存泄漏
  useEffect(() => {
    return () => {
      if (timeoutId.current) {
        clearTimeout(timeoutId.current);
      }
    };
  }, []);

  // 官方示例的获胜判定函数
  const calculateWinner = (squares) => {
    const lines = [
      [0, 1, 2],
      [3, 4, 5],
      [6, 7, 8],
      [0, 3, 6],
      [1, 4, 7],
      [2, 5, 8],
      [0, 4, 8],
      [2, 4, 6],
    ];
    for (let i = 0; i < lines.length; i++) {
      const [a, b, c] = lines[i];
      if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {
        return squares[a];
      }
    }
    return null;
  };

  const handleClick = (index) => {
    // 先检查当前位置是否已被占用,或者已经有赢家,直接终止操作
    const currentWinner = calculateWinner(board);
    if (board[index] || currentWinner) {
      return;
    }

    // 执行落子逻辑
    const updatedBoard = [...board];
    updatedBoard[index] = currentPlayer;
    setBoard(updatedBoard);

    // 检查落子后是否产生赢家
    const newWinner = calculateWinner(updatedBoard);
    if (newWinner) {
      // 启动3秒延迟重置的定时器
      timeoutId.current = setTimeout(() => {
        resetGame();
      }, 3000);
    } else {
      // 没有赢家则切换玩家
      setCurrentPlayer(prev => prev === 'X' ? 'O' : 'X');
      // 清除之前可能存在的未执行定时器(比如中途落子打断了之前的延迟)
      if (timeoutId.current) {
        clearTimeout(timeoutId.current);
        timeoutId.current = null;
      }
    }
  };

  // 渲染棋盘等UI部分(这里省略官方示例的渲染代码)
  return (
    <div className="game">
      {/* 你的棋盘渲染逻辑 */}
    </div>
  );
}

export default TicTacToe;

关键细节说明

  • 定时器的保存与清理:用useRef存储定时器ID,这样即使组件重新渲染,也能拿到同一个定时器引用。在组件卸载的清理函数中清除定时器,避免内存泄漏。
  • 中途清除定时器:如果在延迟重置的3秒内,玩家又进行了操作(虽然我们已经在handleClick开头判断了有赢家就返回,但如果是平局或者其他情况),需要清除之前的定时器,避免不必要的状态重置。
  • 类组件适配:如果是用类组件开发,逻辑类似,只需要把定时器ID存在this.timeoutId中,然后在componentWillUnmount生命周期里执行clearTimeout(this.timeoutId)即可。

内容的提问来源于stack exchange,提问作者Jan Cziżikow

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 03:56:20