React Hangman 游戏:点击状态未正确管理,产生意外行为

2024-05-04

你好,我有 Letters.js,它可以生成 a-z 的可用字母。

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

const Letters = (props) => {
    const [allLetters]=useState(
        ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z']
    );

    const playHandler = (alphabet) => {
        const solution = props.solution.split('');
        console.log(solution);

        if (solution.indexOf(alphabet)<0)
        {
            console.log('incorrect');
            return false;
        }
        else
        {
            console.log('correct');
            return true;
        }
    }

    const availableLetters = [ ...allLetters ].map(
        (alphabet,i) => {
            return (
                <AvailableLetter setSolved={props.setSolved} play={()=>playHandler(alphabet)} correct={()=>props.correct(alphabet)} incorrect={()=>props.incorrect(alphabet)} solution={props.solution} key={i} alphabet={alphabet} />
            );
        }
    );



    return (    
        <div className={classes.Letters}>
            <p>Solution: {props.solution}</p>
            <div className={classes.AvailableLetters}>
                {availableLetters}
            </div>
        </div>
    );
}

export default Letters;

我有可用的信件。在这里,我希望它在第一次点击后可以点击。

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

const AvailableLetter = (props) => {
    // const [show,setShow]=useState(true);
    // const [clicked, setClicked]=useState(false);
    // const [outcome,setOutcome]=useState(false);
    const [clicked,setClicked]=useState(false);

    // if (show)
    // {
    //     setClicked(true);
    // }

    // const play = (alphabet) => {
    //     const solution = props.solution.split('');
    //     if (solution.indexOf(alphabet)<0)
    //     {
    //         return false;
    //     }
    //     else
    //     {
    //         return true;
    //     }
    // }

    const setStuff = () => {
        // setShow(true);
        setClicked(false);
        props.setSolved();
    };
    useEffect( setStuff,[clicked] );

    // useEffect( ()=>setShow(true),[show] );
    // useEffect( ()=>props.setSolved(),[show] );

    if (clicked)         // STRANGELY THIS PART WORKS!!!
    {
        if (props.play())
        {
            props.correct();
            // alert('correct');
        }
        else
        {
            props.incorrect();
            // alert('wrong');
        }
    }

    const attachedClasses = [classes.AvailableLetter];
    const disableLetter = () => {
        attachedClasses.push(classes.Disabled);
        setClicked(true);
    };

    // const letter = <span onClick={disableLetter} className={attachedClasses.join(' ')} >{props.alphabet}</span>;

    let letter=null;
    if (!clicked)
    {
        letter = <span onClick={disableLetter} className={attachedClasses.join(' ')} >{props.alphabet}</span>;
    }
    else if(clicked)    // CODE NEVER GETS HERE!!!!!!!!!!!!!!
    {
        letter = <span className={attachedClasses.join(' ')} >{props.alphabet}</span>;
    }

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

export default AvailableLetter;

它的CSS文件是AvailableLetter.module.css:

.AvailableLetter
{
    border: 1px solid black;
    padding: 10px;
    margin: 3px;
}

.AvailableLetter.Disabled
{
    pointer-events: none;
    background: #aaa;
}

看来我在AvailableLetter中的逻辑是正确的,但它永远不会到达else if(单击)部分,并且字母始终保持可单击。

在AvailableLetter.js内部:如果我使用按钮代替:

<button disable={clicked} onClick={()=>setClicked(true)}>props.alphabet</button>

奇怪的是,即使 setClicked(true) 禁用也不起作用。

但如果我这样做

<button disable>props.alphabet</button>

现在它禁用了。

我感谢您的帮助!

更新: 从 setStuff() 中删除 setClicked(false) 会出现错误:

Error: Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.

您的效果和挂钩的组合创建了一个反馈循环。

这个按钮:

<span onClick={disableLetter} className={attachedClasses.join(' ')} >{props.alphabet}</span>

调用这个函数:

    const disableLetter = () => {
        attachedClasses.push(classes.Disabled);
        setClicked(true);
    };

其中设置clicked to true。一旦发生这种情况,就会产生以下效果:

    const setStuff = () => {
        // setShow(true);
        setClicked(false);
        props.setSolved();
    };
    useEffect( setStuff,[clicked] );

这立即使clicked == false再次。另外值得注意的是setStuff第二次被叫是因为clicked更改值,再次触发效果。什么是setStuff在这种情况下应该做什么?删除对setClicked(false)在该函数中和clicked应保持为true.

我强烈建议清理您的代码,以便更容易遵循。逻辑是这样的:

if (!clicked) {
  // not clicked
} else if (clicked) {
  // clicked 
}

可以很容易地描述如下:

if (clicked) {
  // clicked
} else {
  // not clicked
}

通过这样做,您在调试像您遇到的问题时会省去很多麻烦。

最大更新深度误差

根据您的堆栈跟踪和问题/pastebin 中的代码,您有another这部分引起的循环:

    if (clicked)
    {
        if (props.play())
        {
            props.correct();
            // alert('correct');
        }
        else
        {
            props.incorrect(); // <- this is your trigger
            // alert('wrong');
        }
    }

您应该将此代码移至您的setStuff函数,因此效果仅调用一次。

我还建议重新考虑您的结构,以便您(和其他人)可以更好地遵循您正在做的事情。堆栈跟踪将帮助您解决遇到的任何进一步错误,以便您可以跟踪可能遇到的更多循环的来源。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

React Hangman 游戏:点击状态未正确管理,产生意外行为 的相关文章

  • 使react-leaflet能够离线使用

    我一直在使用反应传单 https github com PaulLeCam react leaflet图书馆 到目前为止运作良好 现在我希望网站预加载尽可能多的图块 以便网络应用程序 也是 PWA 可以在没有互联网的情况下使用 我找到了一些
  • 微前端架构中如何共享redux store?

    我正在尝试创建一个小项目来实现微前端架构 如下微前端 https martinfowler com articles micro frontends html文章 我正在为每个 MFE 微前端 创建多个存储库 并为该应用程序使用 Redux
  • 在 JSPdf 中嵌入二进制文件

    我在用着JsPDF https www npmjs com package jspdf将 html 内容导出到下载的 PDF 考虑以下示例 该示例获取一些 HTML 内容并将其输出到下载的 PDF 文件 使用JsPdf import Rea
  • 如何在 TypeScript React 项目中使用 eslint import 插件启用绝对路径别名?

    我已经安装了eslint plugin import到我的项目 我的目标是使用 import no relative parent imports error 设置禁止在我的项目中进行相对导入以增强可读性 但是 此设置会在我的项目中产生错误
  • 内容丰富的 api markdown 转换为 HTML

    有没有什么简单的方法可以将 Markdown 文本从 Contentful api 转换为 html 代码以显示在 html 页面上 我尝试过使用 pagedown 和一些类似的技术 但似乎没有一个对我有用 我是 Contentful 的客
  • 如何使用 setState 插入 React 的状态数组?

    我正在寻找在反应中修改和数组并在特定索引上插入元素 这就是我的状态 this state arr 我想做的是编译这个arr index random element 反应 js setState 语法 我试图做的是 this setStat
  • 如何为 HOC 创建共享状态?

    我创造了LoadBookHOC包裹着BookDetails and BookSummary成分 LoadBookHOC js const LoadBookHOC InnerComponent gt class LoadBook extend
  • React hooks 状态变量在重新渲染后未更新

    在下面的示例中 我有一个想要更新的元素 水果 数组 并使用更新后的数组执行其他操作 在本例中保存更新后的列表 我的理解是重新渲染状态将更新 但它不在这里 或者状态更新和我的操作之间存在延迟 In the addFruit功能我可以看到 Pe
  • “React”在定义之前就被使用了

    我正在使用 create react app typescript eslint 应用程序 在构建过程中出现这样的错误 Line 1 8 React was used before it was defined typescript esl
  • React Native Expo StackNavigator 重叠通知栏

    我正在尝试为我的 React Native Expo 应用程序实现导航栏 这里有一个问题 dependencies expo 18 0 3 react 16 0 0 alpha 12 react native 0 45 1 react na
  • 我应该如何实现将状态保存到 localStorage?

    CODE var React require react var Recipe require Recipe jsx var AddRecipe require AddRecipe jsx var EditRecipe require Ed
  • ‘state’未定义 no-undef

    我使用教程来学习 React 但我很快就陷入困境 在教程中 他们使用以下代码 import React Component from react class Counter extends Component state count 0 r
  • 为子元素提供属性时,如何为 React.cloneElement 分配正确的类型?

    我正在使用 React 和 Typescript 我有一个充当包装器的反应组件 我希望将其属性复制到其子组件 我正在遵循 React 的使用克隆元素的指南 https facebook github io react blog 2015 0
  • 从父组件触发子组件内部的函数

    如何从父组件触发子组件内部的函数 以与抽屉导航相同的风格进行操作 他们这样做 this props navigation toggleDrawer 来自父母 我怎样才能做同样的事情 如果我正确理解你的问题 我认为你有点混淆了 您显示的示例是
  • 什么时候使用useEffect?

    我目前正在查看 React 文档的 useEffect 示例 import React useState useEffect from react function Example const count setCount useState
  • JSX 中的“导出默认值”有什么作用?

    我想问最后一句的含义和作用 导出默认 HelloWorld 但我找不到任何有关它的教程 hello world jsx import React from react class HelloWorld extends React Compo
  • 检查所有子组件是否已安装

    有什么办法可以检测孩子是否已经挂载了吗 当我初始化同位素时 必须安装所有子组件才能初始化 超时时间为 5 毫秒 它按预期工作 但我确信有更好的方法 componentDidMount function var container this
  • 在 Heroku 上配置单页面 Create-React-App

    使用 Firebase Hosting 当您部署应用程序时有人问你 https stackoverflow com questions 37667626 firebase cli configure as a single page app
  • 如何将变量传递给函数引用?

    在 React Native 中 当你有需要在渲染时运行并且必须传递变量的函数时 大多数人建议应该使用 onPress gt this functionName variable 然而 当处理大型列表和复杂组件时 您必须优化代码 为每个 r
  • 如何在 React Native 中做最后一个子选择器?

    我使用Scrollview 里面有3个视图 我在它们之间留了一个间隙 例如 marginRight 5 但我不希望在最后一个视图中出现这种间隙 这就是为什么我需要这种东西 你能帮助我吗 应用这个你就可以实现你在寻找什么 const styl

随机推荐