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

React Hooks状态为何在Guess组件显示后恢复初始值?

猜数字游戏状态重置问题解决方案

问题描述

开发猜数字游戏时,点击盒子5次生成随机数,组件挂载时生成包含5个随机数的初始数组;输入数字后检查两个数组是否包含该数字并对应上色。但当Guess组件显示后,所有Hook状态都会恢复为初始值。

核心原因

Guess组件内部重复调用了useHook(),每个useHook调用都会创建完全独立的状态实例。也就是说,Main组件和Guess组件使用的是两套毫无关联的状态,并非Main的状态被重置,而是Guess在使用自己的全新初始状态。

解决方案

1. 统一状态管理,移除Guess内的useHook调用

让所有状态和逻辑仅在Main组件的useHook实例中维护,通过props将需要的方法和状态传递给Guess组件。

修改后的代码

Main.tsx

import { Guess } from "./Guess";
import { useHook } from "./Hook";
import { Loading } from "./Loading";
import "./styles.css";

export const Main = () => {
  // 取出所有需要的状态和方法
  const { loading, count, handleClick, randArr, handleKeyUp, guess } = useHook();

  return (
    <div className="main">
      {!loading && count < 5 && (
        <div className='click-container'>
          {Array.from({ length: 5 }).fill('').map((_, i: number) =>
            <div onClick={handleClick} className='box' key={i}>Click</div>
          )}
        </div>
      )}
      {loading && <Loading count={count} />}
      {!loading && count >= 5 && (
        // 将handleKeyUp和guess通过props传递给Guess
        <Guess 
          arr={randArr} 
          handleKeyUp={handleKeyUp} 
          guess={guess} 
        />
      )}
    </div>
  );
};

Guess.tsx

import React, { useEffect } from "react";
import "./styles.css";

// 复用Hook中的guess类型
type guessType = {
  keyNum: number;
  isContain: boolean;
};

// 更新props类型,包含传递的方法和状态
type props = {
  arr: number[];
  handleKeyUp: (e: { key: string }) => void;
  guess: guessType[];
};

export const Guess: React.FC<props> = (props) => {
  const { handleKeyUp, guess } = props;

  useEffect(() => {
    window.addEventListener("keyup", handleKeyUp);

    return () => {
      window.removeEventListener("keyup", handleKeyUp);
    };
  }, [handleKeyUp]);

  console.log(props.arr, " this is props arr ");
  return (
    <div className="content">
      <div>
        <p>Guesses: </p>
        <div className="guess-list">
          {guess.map((item, i: number) =>
            <p 
              key={i} 
              className={item.isContain ? 'guess-num-true': 'guess-num-false'} 
            >
              {item.keyNum}
            </p>
          )}
        </div>
      </div>
    </div>
  );
};

Hook.tsx(修复类型匹配问题)

import { useEffect, useState } from 'react'

export const useHook = () => {
  type guessType = {
    keyNum: number
    isContain: boolean
  }

  const [disable, setDisable] = useState(true)
  const [randArr, setRandArr] = useState<number[]>([])
  const [initialArr, setInitialArr] = useState<number[]>([])
  const [count, setCount] = useState<number>(0)
  const [loading, setLoading] = useState(true)
  const [guess, setGuess] = useState<guessType[]>([])

  const randomNum = () => {
    return Math.floor(Math.random() * (9 - 0 + 1) + 0);
  }

  useEffect(() => {
    const handleInitialArr = () => {
      for (let i = 0; i < 5; i++) {
        let num = randomNum()
        setInitialArr((prev) => [...prev, num])
      }
    }
    handleInitialArr()
  }, [])

  const handleClick = () => {
    if (!disable) {
      let num = randomNum()
      setRandArr((prev)=> [...prev, num])
      setCount((prev) => prev + 1)
      setDisable(true)
      setLoading(true)
    }
  }

  useEffect(()=> {
    const handleLoading = () => {
      setTimeout(() => {
        setLoading(false)
      }, 500)
    }

    const handleRound = () => {
      setDisable(false)
    }

    handleLoading()
    handleRound()
  }, [count])

  const handleKeyUp = ({key}) => {
    const isNumber = /^[0-9]$/i.test(key)
    if (isNumber) {
      // 修复:将字符串key转为数字,避免和数字数组的includes判断不匹配
      const numKey = parseInt(key, 10)
      if (randArr.includes(numKey) && initialArr.includes(numKey)) {
        setGuess((prev) => [...prev, {keyNum: numKey, isContain: true}])
        console.log(' they both have this number')
      } else {
        setGuess((prev) => [...prev, {keyNum: numKey, isContain: false}])
        console.log(' they both do not contain this number ')
      }
    }
  }

  return {
    count, 
    loading,
    handleClick, 
    randArr,
    handleKeyUp,
    guess
  }
}

关键修改说明

  • 确保状态唯一:所有状态仅在Main组件的useHook实例中维护,避免多实例导致的状态割裂
  • 数据统一传递:通过props将方法和状态传递给Guess,保证两者使用同一套数据
  • 修复类型错误:将键盘事件的字符串key转为数字,解决数组includes判断失效的问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 07:35:19