我正在制作子手游戏。单击字母后,它将不再不可单击。
以下是codeandbox的简化版本: https://codesandbox.io/s/intelligent-cori-6b80q
在沙箱中,单击字母时,将更改为“已单击!”。一切似乎都很好。
但是在我的项目中,我得到了奇怪的行为。
AvailableLetter.js
const AvailableLetter = (props) => {
const [clicked,setClicked]=useState(false);
const setStuff = () => {
setClicked(false); // If I delete this I get Error: Maximum update depth exceeded.
props.setSolved();
};
useEffect( setStuff,[clicked] );
if (clicked) // IF CLICKED REMAINS TRUE, EVERY LETTER GETS PLAYED.
{
if (props.play())
{
props.correct();
}
else
{
props.incorrect();
}
}
const disableLetter = () => {
setClicked(true);
};
let letter=span onClick={disableLetter}>{props.alphabet}</span>;
if(clicked) // CODE NEVER GETS HERE!!!!!!!!!!!!!!
{
letter = <span>{props.alphabet}</span>;
}
return (
<Ax> // Ax is a high order class, just a wrapper
{letter}
</Ax>
);
}
即使被单击,字母仍然保持可单击状态。这不是我想要的。
每个字母均由Letters.js呈现,后者会以a-z格式输入并生成自定义的AvailableLetter。
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} />
);
}
);
所以这里要解决的问题是:
- Letters remain clickable even after a click
- If setClicked(false) is removed it causes an infinite loop
const setStuff = () => {
setClicked(false); // if removed causes infinite loop
props.setSolved();
};
所有这些都很奇怪,因为在codeandbox中,我不需要将setEffect()中的clicked设置为false。
您可以在此处查看所有代码:https://github.com/gunitinug/hangmanerrors/tree/master/src 请查看项目代码,时间不长。
答案 0 :(得分:0)
您需要了解useEffect
的工作方式。每当状态更改时,都会调用useEffect
并执行作为回调传递给setStuff
的处理程序(在您的情况下为useEffect
)。
因此,setStuff
不断更新状态,useEffect
不断被调用。因此,您看到错误Error: Maximum update depth exceeded
。
如下所示更改代码:
const AvailableLetter = (props) => {
const [clicked, setClicked] = useState(false);
const setStuff = () => {
if(clicked) {
if (props.play()) {
props.correct();
}
else {
props.incorrect();
}
setClicked(false);
props.setSolved();
}
};
useEffect( setStuff, [clicked] );
return (
<Ax>
<button onClick={() => setClicked(true)} disabled={clicked}>{props.alphabet}</button>
</Ax>
);
}
如您对问题的评论中所述,这可能不是最好的方法,但是我的代码可以解决您的问题。
答案 1 :(得分:0)
这是一个结构性问题,我不得不委托处理程序函数并将状态声明给父组件Letters.js
我必须使其如丝般顺滑:p
import React, {useState} from 'react';
import AvailableLetter from './AvailableLetter/AvailableLetter';
import DisabledLetter from './DisabledLetter/DisabledLetter';
import classes from './Letters.module.css';
const Letters = (props) => {
const [lettersMap, setLettersMap]=useState(
{
"a":false,"b":false,"c":false,"d":false,"e":false,"f":false,"g":false,"h":false,"i":false,"j":false,"k":false,"l":false,"m":false,"n":false,"o":false,"p":false,"q":false,"r":false,"s":false,"t":false,"u":false,"v":false,"w":false,"x":false,"y":false,"z":false
}
);
const updateClickedHandler = (letter) => {
setLettersMap(
{
...lettersMap,[letter]:true
}
);
};
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 renderedLetters = Object.keys(lettersMap).map(
(letter,i)=>{
if (!lettersMap[letter]) //letter is not yet clicked
{
return (
<AvailableLetter updateClicked={updateClickedHandler} setSolved={props.setSolved} play={()=>playHandler(letter)} correct={()=>props.correct(letter)} incorrect={()=>props.incorrect(letter)} solution={props.solution} key={i} alphabet={letter} />
)
}
else //letter is clicked
{
return (
<DisabledLetter alphabet={letter} />
)
}
}
);
return (
<div className={classes.Letters}>
<p>Solution: {props.solution}</p>
<div className={classes.AvailableLetters}>
{renderedLetters}
</div>
</div>
);
}
export default Letters;
和
import React from 'react';
import classes from './AvailableLetter.module.css';
import Ax from '../../hoc/Ax';
const AvailableLetter = (props) => {
const setStuff = () => {
if (props.play()) {
props.correct();
}
else {
props.incorrect();
}
props.updateClicked(props.alphabet);
props.setSolved();
};
return (
<Ax>
<span className={classes.AvailableLetter} onClick={setStuff}>{props.alphabet}</span>
</Ax>
);
}
export default AvailableLetter;
最后,我添加了另一个名为DisabledLetter.js的组件
import React from 'react';
import classes from './DisabledLetter.module.css';
const DisabledLetter = (props) => {
return (
<span className={classes.DisabledLetter} >{props.alphabet}</span>
);
};
export default DisabledLetter;
您可以在此处查看整个源 https://github.com/gunitinug/hangmanclicked/tree/master/src ;)
但是发现了一个问题,当游戏解决后,我需要再点击一个字母以显示“ YOU WIN”消息。
我死后立即显示“游戏结束”。