Reactjs 反应问题:错误:超过最大更新深度

Reactjs 反应问题:错误:超过最大更新深度,reactjs,state,lifecycle,effect,Reactjs,State,Lifecycle,Effect,您好,我有Letters.js,它为a-z生成了AvailableLetter import React, {useState} from 'react'; import AvailableLetter from './AvailableLetter/AvailableLetter'; import classes from './Letters.module.css'; const Letters = (props) => { const [allLetters]=useSta

您好,我有Letters.js,它为a-z生成了AvailableLetter

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;
似乎我在AvailableLetter中的逻辑是正确的,但如果(单击)部分和字母始终保持可单击状态,则它永远不会到达else

Inside AvailableLetter.js:如果改用button:

<button disable={clicked} onClick={()=>setClicked(true)}>props.alphabet</button>
setClicked(true)}>props.alphabet
奇怪的是,即使单击设置,禁用也不起作用(true)

但如果我这样做了

<button disable>props.alphabet</button>
props.alphabet
现在它禁用了

从setStuff()中删除setClicked(false)时出错:

错误:超过最大更新深度。当组件在componentWillUpdate或componentDidUpdate内重复调用setState时,可能会发生这种情况。React限制嵌套更新的数量以防止无限循环

我感谢你的帮助

更新: 我一直在尝试使用称为“渲染”的额外状态。我一直不成功,但正在进步

更新的AvailableLetter.js:

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 unclickable span is rendered set to true.
    const [rendered,setRendered]=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);
        rendered&&setClicked(false);     // CHANGED THIS!!!!!!
        props.setSolved();
    };
    useEffect( setStuff,[clicked,rendered] );

    // 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&&setRendered(true))    // CAUSES INFINITE LOOP
    {
        letter = <span className={attachedClasses.join(' ')} >{props.alphabet}</span>;
    }

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

export default AvailableLetter;
import React,{useState,useffect}来自“React”;
从“./AvailableLetter.module.css”导入类;
从“../../hoc/Ax”导入Ax;
const AvailableLetter=(道具)=>{
//const[show,setShow]=useState(true);
//const[clicked,setClicked]=useState(false);
//const[output,setoutput]=useState(false);
const[clicked,setClicked]=useState(false);
//如果呈现“不可拾取范围”,请将其设置为true。
const[rendered,setRendered]=useState(false);
//如果(显示)
// {
//setClicked(true);
// }
//常量播放=(字母表)=>{
//const solution=props.solution.split(“”);
//if(解决方案索引OF(字母表){
//设置显示(正确);
渲染&&setClicked(false);//更改此项!!!!!!
props.setSolved();
};
useEffect(设置凝灰岩,[单击,渲染]);
//useffect(()=>setShow(true),[show]);
//useffect(()=>props.setSolved(),[show]);
如果(点击)//奇怪的是,这部分工作!!!
{
if(props.play())
{
props.correct();
//警惕(“正确”);
}
其他的
{
props.不正确();
//警惕(“错误”);
}
}
const attachedclass=[classes.AvailableLetter];
const disableLetter=()=>{
attachedClasses.push(类.禁用);
setClicked(true);
};
//常量字母={props.alphabet};
让字母=null;
如果(!单击)
{
字母={props.alphabet};
}
else if(单击&&setRendered(true))//会导致无限循环
{
字母={props.alphabet};
}
返回(
{字母}
);
}
导出默认值AvailableLetter;
到目前为止,修改后的版本导致无限循环

我也试过了

else if(clicked&&!rendered?setRendered(true):null)    // CODE NEVER GETS HERE!!!!!!!!!!!!!!
{
   letter = <span className={attachedClasses.join(' ')} >{props.alphabet}</span>;
}
else if(单击&&!rendered?setRendered(true):null)//代码永远不会出现在这里!!!!!!!!!!!!!!
{
字母={props.alphabet};
}

但是这个时间字母始终是可点击的,不会变灰。

这是代码的痕迹。我将解释为什么您会得到这两种结果

letter = <span onClick={disableLetter} className={attachedClasses.join(' ')} >{props.alphabet}</span>;
设置
setClicked(false)
触发重新加载的反应。此代码在

 else if(clicked)    // CODE NEVER GETS HERE!!!!!!!!!!!!!!
这就是为什么从未调用此函数。
setStuff()
在每次渲染后都会设置
setClicked(false)
,并且每次调用
setClicked(true)
时都会进行渲染


删除
setClicked(false)
会使你陷入无限循环。props.setSolve()也会导致重新渲染。每次你的应用渲染时,它都会调用props.setSolve()

以下是代码的跟踪。我将解释为什么你会得到这两种结果

letter = <span onClick={disableLetter} className={attachedClasses.join(' ')} >{props.alphabet}</span>;
设置
setClicked(false)
触发重新加载的反应。此代码在

 else if(clicked)    // CODE NEVER GETS HERE!!!!!!!!!!!!!!
这就是为什么从未调用此函数。
setStuff()
在每次渲染后都会设置
setClicked(false)
,并且每次调用
setClicked(true)
时都会进行渲染


移除
setClicked(false)
会让你陷入无限循环。props.setSolve()也会导致重新渲染。每次你的应用渲染时,它都会调用props.setSolve()

这能回答你的问题吗?这能回答你的问题吗?所以我需要在setClicked(false)之前渲染字母。这将修复“代码永远不会到达这里…”。但您可能仍然有不想要的结果。即使在设置为“设置单击”(false)之后,您仍然在将“单击”设置为“真”之后将其设置为“假”(这违背了使用“设置单击”的目的,也不会禁用按钮)一般来说,此代码可能很难调试。我建议简化代码并添加打印语句以尝试调试。这里的问题实际上是不必要的代码重新呈现,这会导致代码无法运行或无限循环。如果您能够找出导致重新呈现的原因,那么您可以更轻松地调试未来的错误。因此,我需要在setClicked(false)之前呈现字母。这将修复“代码永远不会到达这里…”。但您可能仍然会有不想要的结果。即使setClicked(false)在设置为true之后,您仍然会将click设置为false(这与使用setClicked的目的不符,也不会禁用您的按钮)一般来说,此代码可能很难调试。我建议简化代码并添加打印语句以尝试调试。这里的问题实际上是不必要的代码重新呈现,这会导致代码无法运行或无限循环。如果您能够找出导致重新呈现的原因,那么您可以更轻松地调试未来的错误。
 else if(clicked)    // CODE NEVER GETS HERE!!!!!!!!!!!!!!