Reactjs 反应问题:错误:超过最大更新深度
您好,我有Letters.js,它为a-z生成了AvailableLetterReactjs 反应问题:错误:超过最大更新深度,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
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!!!!!!!!!!!!!!