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

时间:2019-12-09 23:53:35

标签: reactjs state lifecycle effect

enter image description here

您好,我有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.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 (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。

在AvailableLetter.js内部:如果我改用按钮:

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

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

但如果我这样做

<button disable>props.alphabet</button>

现在它将禁用。

从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;

到目前为止,修改后的版本会导致无限循环!

我也尝试过

else if(clicked&&!rendered?setRendered(true):null)    // CODE NEVER GETS HERE!!!!!!!!!!!!!!
{
   letter = <span className={attachedClasses.join(' ')} >{props.alphabet}</span>;
}

但是这次的信件总是可点击的,并且不会变灰。

1 个答案:

答案 0 :(得分:0)

这是代码的痕迹。我会解释为什么您会同时获得两个结果

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

onClick调用disableLetter设置setClicked(true)。当设置了运行代码的状态

时,React重新渲染
const setStuff = () => {
    // setShow(true);
    setClicked(false);
    props.setSolved();
};

设置setClicked(false)触发会重新加载。该代码位于

之前
 else if(clicked)    // CODE NEVER GETS HERE!!!!!!!!!!!!!!

这就是为什么这种情况永远不会被调用的原因。 setStuff()将始终在每次渲染后设置setClicked(false),并且每次调用setClicked(true)时都会渲染{p>

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