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

React猜词游戏点击状态管理异常:字母点击后无法禁用

Fixing Click State Management Issues in React Word Guess Game

Let's break down the root causes of your problems and walk through concrete fixes:

Problem Breakdown & Solutions

1. The else if(clicked) branch never executes

This happens because your useEffect immediately resets the clicked state: when you click a letter, disableLetter sets clicked=true, but the useEffect (which depends on clicked) runs right after and calls setClicked(false). This means clicked flips back to false instantly, so the else if(clicked) branch never gets a chance to render.

Additionally, running props.correct()/props.incorrect() directly in the component's render phase is a mistake—this will trigger those callbacks every time the component re-renders, leading to unnecessary state updates and potential bugs.

2. disable={clicked} doesn't work on button elements

First, React uses the camelCase property disabled (note the trailing "d") for disabling buttons, not disable. Second, even if you used the correct property name, the quick reset of clicked to false means the condition never stays true long enough to disable the button.

3. Removing setClicked(false) causes infinite loops

Without resetting clicked, the state stays true, and your render-phase if(clicked) check keeps calling props.correct()/props.incorrect(). These callbacks trigger state updates in the parent component, which re-renders the AvailableLetter child. The child then re-runs the if(clicked) check, triggering another parent update—creating an infinite loop.


Full Fixed Code

Updated AvailableLetter.js

We'll move the guess logic to the click handler, remove the broken useEffect, and keep the clicked state persistent after a click:

import React, { useState } from 'react';
import classes from './AvailableLetter.module.css';
import Ax from '../../hoc/Ax';

const AvailableLetter = (props) => {
  const [clicked, setClicked] = useState(false);

  // Handle click and guess logic in one place
  const handleLetterClick = () => {
    if (clicked) return; // Prevent duplicate clicks
    
    setClicked(true); // Mark letter as clicked
    const isCorrect = props.play();
    
    // Trigger parent callbacks only once on click
    if (isCorrect) {
      props.correct(props.alphabet);
    } else {
      props.incorrect();
    }
    props.setSolved();
  };

  // Build class list dynamically
  const attachedClasses = [classes.AvailableLetter];
  if (clicked) {
    attachedClasses.push(classes.Disabled);
  }

  // Single element render (no need for if/else branches)
  const letter = (
    <span 
      onClick={handleLetterClick} 
      className={attachedClasses.join(' ')}
      // If using a button instead, use this code:
      // <button 
      //   onClick={handleLetterClick} 
      //   className={attachedClasses.join(' ')}
      //   disabled={clicked}
      // >
    >
      {props.alphabet}
    </span>
  );

  return (
    <Ax>
      {letter}
    </Ax>
  );
};

export default AvailableLetter;

Quick Note for Letters.js

Make sure your parent component's correct handler accepts a letter parameter (since we're passing props.alphabet now):

// Example parent component correct handler
const correctHandler = (guessedLetter) => {
  // Logic to update solved letters, e.g., add guessedLetter to a solved set
};

This fixes all three issues:

  • Clicked letters stay disabled (the Disabled class is applied and stays applied)
  • Buttons will properly disable when using disabled={clicked}
  • No more infinite loops, since we only trigger parent callbacks once per click (not on every render)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:56:43