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

时间:2020-06-17 21:22:35

标签: javascript reactjs

我很容易找到其他颜色的应用程序。游戏的目的只是从场景中选择不同的颜色。 5点后,该设置将渲染为3x3而不是2x2。但是我遇到了这个错误

“未捕获的不变违反:超过最大更新深度。当组件重复调用componentWillUpdate或componentDidUpdate内部的setState时,可能会发生这种情况。React限制嵌套更新的数量以防止无限循环。 固定为“

我试图将其上传到codepen,但是由于无限循环,一旦遇到错误,它似乎会杀死该应用程序。 我仔细阅读了这个问题,他们说componentDidUpdate中的setState可能会导致另一个更新,然后inf循环,但是我不确定我的问题是怎么引起的。

temperature = int(input("What is the temperature? "))

if temperature == 26:
    print("The weather is average")
elif temperature > 26:
    print("The weather is hot")
elif temperature < 26:
    print("It's a cold day")
else:
    print("Invalid")

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

2 个答案:

答案 0 :(得分:1)

您可以在增加分数后立即进行检查:

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

升级功能:

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

在构造函数中绑定它:

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>

答案 1 :(得分:0)

在评论中回答。在isMatch中移动了代码或将其保留在componentDidUpdate中,但还对代码进行了条件检查以检查prevState