您好,我有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>;
}
但是这次的信件总是可点击的,并且不会变灰。
答案 0 :(得分:0)
这是代码的痕迹。我会解释为什么您会同时获得两个结果
letter = <span onClick={disableLetter} className={attachedClasses.join(' ')} >{props.alphabet}</span>;
onClick调用disableLetter设置setClicked(true)
。当设置了运行代码的状态
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()