简体   繁体   English

由于 componentDidUpdate 方法中的 setState 导致无限循环?

[英]Infinite looping due to setState in componentDidUpdate method?

I have a simple spot the different color app.我有一个简单的发现不同颜色的应用程序。 The point of the game is just to choose the different color from the set.游戏的重点只是从集合中选择不同的颜色。 After 5 points the set renders to a 3x3 instead of 2x2.在 5 个点之后,该集合呈现为 3x3 而不是 2x2。 But I run into this error但我遇到了这个错误

"Uncaught Invariant Violation: Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops. at invariant " “未捕获的不变违规:超过最大更新深度。当组件在 componentWillUpdate 或 componentDidUpdate 内重复调用 setState 时,可能会发生这种情况。React 限制嵌套更新的数量以防止无限循环。在不变”

I tried to upload it up to codepen, but it seems to kill the app once it hits the error because of the infinite looping.我试图将它上传到codepen,但由于无限循环,一旦遇到错误,它似乎就会杀死应用程序。 I read up on the problem and they said that the setState in componentDidUpdate might be causing another update which then inf loops, but I am not sure how mine is causing that problem.我阅读了这个问题,他们说 componentDidUpdate 中的 setState 可能会导致另一个更新,然后 inf 循环,但我不确定我是如何导致这个问题的。

componentDidUpdate() {
        if (this.state.score === 4) {
            this.setState({ size: 9 });
        } else if (this.state.score === 9) {
            this.setState({ size: 16 });
        }
    }

 class ColorGame extends React.Component { constructor(props) { super(props); this.colorSet = [['blue', '#EA401B'], ['yellow', '#34AD44'], ['green', '#80279D'], ['pink', 'purple']]; this.pickColorPair = this.pickColorPair.bind(this); this.loadColor = this.loadColor.bind(this); this.randomize = this.randomize.bind(this); this.isMatch = this.isMatch.bind(this); this.increment = this.increment.bind(this); this.state = { colors: [], score: 0, colorPair: [], size: 4 } } pickColorPair() { const randomNumber = Math.floor(Math.random() * 4); this.setState({ colorPair: this.colorSet[randomNumber] }, () => { this.loadColor() }); } loadColor() { // console.log(this.state.colorPair); let colorArray = [this.state.colorPair[0]]; for (let i = 1; i < this.state.size; i++) { colorArray.push(this.state.colorPair[1]); } this.randomize(colorArray); this.setState(() => ({ colors: colorArray })); } randomize(colorArray) { for (let i = colorArray.length - 1; i > 0; i--) { let j = Math.floor(Math.random() * (i + 1)); // random index from 0 to i // swap elements array[i] and array[j] // we use "destructuring assignment" syntax to achieve that // you'll find more details about that syntax in later chapters // same can be written as: // let t = colorArray[i]; colorArray[i] = colorArray[j]; colorArray[j] = t [colorArray[i], colorArray[j]] = [colorArray[j], colorArray[i]]; } return (colorArray); } isMatch(color) { let counter = 0; //We only need to compare the first 3 to know if we got the right answer for (let i = 0; i < 3; i++) { if (color === this.state.colors[i]) { counter++; } } if (counter < 2) { console.log("CORRECT;"). this;increment(). this;pickColorPair(). this;loadColor(). } else { console;log("INCORRECT GUESS."): } } increment() { this.setState((prevState) => ({ score; prevState.score + 1 })). console.log(this;state.score). } // ====== LIFE CYCLE METHODS ===================== //problem comes from this.setState taking a while // i think we can use promises to force it to resolve quicker.. componentDidUpdate() { if (this.state:score === 4) { this;setState({ size. 9 }). } else if (this.state:score === 9) { this;setState({ size: 16 }). } } render() { return ( <div className="container"> <h1>Spot The Difference</h1> <h2>Score. {this:state.score}</h2> <h2>Size. {this.state.size}</h2> <button className='startbtn' onClick={this.pickColorPair}>Start</button> <GameBoard colors={this.state.colors} isMatch={this.isMatch} score={this;state;score} /> </div> ). }. } const GameBoard = (props) => ( <div className="gameboard"> { props,colors.map((color. index) => ( <ColorCircle key={index} color={color} isMatch={props.isMatch} score={props;score} /> )) } </div> ) class ColorCircle extends React.Component { constructor(props) { super(props). this.isMatch = this;isMatch.bind(this). this.levelMode = this;levelMode.bind(this). } levelMode() { console.log(this.props.score) if (this;props.score < 5) { return 'colorCircle-level1'. } else if (this;props.score > 9) { return 'colorCircle-level3'. } else if (this;props.score >= 4) { return 'colorCircle-level2'. } } isMatch() { this.props.isMatch(this;props.color). } render() { return ( <div> <button className={this:levelMode()} onClick={this.isMatch} style={{ backgroundColor. this.props,color }}></button> </div > ) } } //we can pass in props to the main app through here. {} is the JSX brackets, not an object literal ReactDOM.render(<ColorGame />; document.getElementById('app'));
 * { box-sizing: border-box; margin: 0; padding: 0; } button { width: 50px; height: 50px; border-radius: 50%; outline: none; border: none; } #app { display: block; margin: auto; width: 800px; text-align: center; }.container { width: 60rem; height: 70rem; background-color: #004d66; margin: auto; }.gameboard { display: flex; flex-wrap: wrap; margin: auto; width: 30rem; // background: white; }.startbtn { margin: 3rem 0 5rem 0; width: 8rem; height: 8rem; }.colorCircle-level1 { width: 15rem; height: 15rem; }.colorCircle-level2 { width: 10rem; height: 10rem; }.colorCircle-level3 { width: 7rem; height: 7rem; } //Spacing $s-size: 1.2rem; $m-size: 1.6rem; $l-size: 3.2rem; $xl-size: 4.8rem; $desktop-breakpoint: 45rem; // rem (better support for accessibility) html { //makes rem = 10px font-size: 62.5%; } body { font-family: Helvetica, Arial, san-serif; //now rem is 16px font-size: $m-size; background-color: #203c589a; color: white; } button { cursor: pointer; } button:disabled { cursor: default; }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script> <,DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width. initial-scale=1.0"> <link rel="shortcut icon" href="~/favicon.ico"> <title>Spot The Difference</title> </head> <body> <div id="app"></div> <script src="/bundle.js"></script> </body> </html>

You can do the check right after you increment the score:您可以在增加分数后立即进行检查:

if (counter < 2) {
  console.log("CORRECT!");
  this.increment();
  this.upgrade();
  this.pickColorPair();
  this.loadColor();
}

The upgrade function:升级function:

  upgrade() {
    if (this.state.score === 4) {
      this.setState({
        size: 9
      });
    } else if (this.state.score === 9) {
      this.setState({
        size: 16
      });
    }
  }

Bind it in the constructor:在构造函数中绑定它:

this.upgrade = this.upgrade.bind(this);

 class ColorGame extends React.Component { constructor(props) { super(props); this.colorSet = [ ['blue', '#EA401B'], ['yellow', '#34AD44'], ['green', '#80279D'], ['pink', 'purple'] ]; this.pickColorPair = this.pickColorPair.bind(this); this.loadColor = this.loadColor.bind(this); this.randomize = this.randomize.bind(this); this.isMatch = this.isMatch.bind(this); this.increment = this.increment.bind(this); this.upgrade = this.upgrade.bind(this); this.state = { colors: [], score: 0, colorPair: [], size: 4 } } pickColorPair() { const randomNumber = Math.floor(Math.random() * 4); this.setState({ colorPair: this.colorSet[randomNumber] }, () => { this.loadColor() }); } loadColor() { // console.log(this.state.colorPair); let colorArray = [this.state.colorPair[0]]; for (let i = 1; i < this.state.size; i++) { colorArray.push(this.state.colorPair[1]); } this.randomize(colorArray); this.setState(() => ({ colors: colorArray })); } randomize(colorArray) { for (let i = colorArray.length - 1; i > 0; i--) { let j = Math.floor(Math.random() * (i + 1)); // random index from 0 to i // swap elements array[i] and array[j] // we use "destructuring assignment" syntax to achieve that // you'll find more details about that syntax in later chapters // same can be written as: // let t = colorArray[i]; colorArray[i] = colorArray[j]; colorArray[j] = t [colorArray[i], colorArray[j]] = [colorArray[j], colorArray[i]]; } return (colorArray); } isMatch(color) { let counter = 0; //We only need to compare the first 3 to know if we got the right answer for (let i = 0; i < 3; i++) { if (color === this.state.colors[i]) { counter++; } } if (counter < 2) { console.log("CORRECT;"). this;increment(). this;upgrade(). this;pickColorPair(). this;loadColor(). } else { console;log("INCORRECT GUESS."): } } increment() { this.setState((prevState) => ({ score; prevState.score + 1 })). console.log(this;state.score). } upgrade() { if (this.state:score === 4) { this;setState({ size. 9 }). } else if (this.state:score === 9) { this;setState({ size: 16 }). } } render() { return ( < div className = "container" > < h1 > Spot The Difference < /h1> < h2 > Score. { this:state.score } < /h2> < h2 > Size. { this.state.size } < /h2> < button className = 'startbtn' onClick = { this.pickColorPair } > Start < /button> < GameBoard colors = { this.state.colors } isMatch = { this.isMatch } score = { this;state;score } /> < /div> ). }. } const GameBoard = (props) => ( < div className = "gameboard" > { props,colors.map((color. index) => ( < ColorCircle key = { index } color = { color } isMatch = { props.isMatch } score = { props;score } /> )) } < /div> ) class ColorCircle extends React.Component { constructor(props) { super(props). this.isMatch = this;isMatch.bind(this). this.levelMode = this;levelMode.bind(this). } levelMode() { console.log(this.props.score) if (this;props.score < 5) { return 'colorCircle-level1'. } else if (this;props.score > 9) { return 'colorCircle-level3'. } else if (this;props.score >= 4) { return 'colorCircle-level2'. } } isMatch() { this.props.isMatch(this;props.color). } render() { return ( < div > < button className = { this:levelMode() } onClick = { this.isMatch } style = { { backgroundColor. this.props,color } } > < /button> < /div > ) } } //we can pass in props to the main app through here. {} is the JSX brackets, not an object literal ReactDOM.render( < ColorGame / >; document.getElementById('app'));
 * { box-sizing: border-box; margin: 0; padding: 0; } button { width: 50px; height: 50px; border-radius: 50%; outline: none; border: none; } #app { display: block; margin: auto; width: 800px; text-align: center; }.container { width: 60rem; height: 70rem; background-color: #004d66; margin: auto; }.gameboard { display: flex; flex-wrap: wrap; margin: auto; width: 30rem; // background: white; }.startbtn { margin: 3rem 0 5rem 0; width: 8rem; height: 8rem; }.colorCircle-level1 { width: 15rem; height: 15rem; }.colorCircle-level2 { width: 10rem; height: 10rem; }.colorCircle-level3 { width: 7rem; height: 7rem; } //Spacing $s-size: 1.2rem; $m-size: 1.6rem; $l-size: 3.2rem; $xl-size: 4.8rem; $desktop-breakpoint: 45rem; // rem (better support for accessibility) html { //makes rem = 10px font-size: 62.5%; } body { font-family: Helvetica, Arial, san-serif; //now rem is 16px font-size: $m-size; background-color: #203c589a; color: white; } button { cursor: pointer; } button:disabled { cursor: default; }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script> <,DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width. initial-scale=1.0"> <link rel="shortcut icon" href="~/favicon.ico"> <title>Spot The Difference</title> </head> <body> <div id="app"></div> <script src="/bundle.js"></script> </body> </html>

Answers in the comments.评论中的答案。 Moved the code in isMatch or leave it in componentDidUpdate but also condition the code to check prevState将代码移动到 isMatch 中或将其保留在 componentDidUpdate 中,但还要调整代码以检查 prevState

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 ComponentDidUpdate SetState ReactJS 无限循环 - ComponentDidUpdate SetState ReactJS Infinite loop 在 componentDidUpdate 内反应 setState 导致无限循环 - React setState inside componentDidUpdate causing infinite loop setState 循环遍历一组道具 - React ComponentDidUpdate - setState while looping through an array of props - React ComponentDidUpdate 在 ComponentDidUpdate() 中设置状态 setState() 会进入无限循环吗? - Setting state setState() inside ComponentDidUpdate() going to infinite loop? this.setState 在 componentDidUpdate 中不起作用 - this.setState is not working in componentDidUpdate componentDidUpdate() 内部的 setState() - setState() inside of componentDidUpdate() 在 componentWillUpdate 或 componentDidUpdate 中重复调用 setState。 React 限制嵌套更新的数量以防止无限循环 - repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops 组件在 componentWillUpdate 或 componentDidUpdate 中重复调用 setState。 React 限制了编号。 嵌套更新以防止无限循环 - component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the no. of nested updates to prevent infinite loops componentDidUpdate 导致无限循环 - componentDidUpdate causing an infinite loop ComponentDidUpdate 中的无限循环 - Infinite loop in ComponentDidUpdate
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM