为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

四季花海 2022-10-08 17:44:05
我有一个简单的发现不同颜色的应用程序。游戏的重点只是从集合中选择不同的颜色。在 5 个点之后,该集合呈现为 3x3 而不是 2x2。但我遇到了这个错误“未捕获的不变违规:超过最大更新深度。当组件在 componentWillUpdate 或 componentDidUpdate 内重复调用 setState 时,可能会发生这种情况。React 限制嵌套更新的数量以防止无限循环。在不变”我试图将它上传到codepen,但由于无限循环,一旦遇到错误,它似乎就会杀死应用程序。我阅读了这个问题,他们说 componentDidUpdate 中的 setState 可能会导致另一个更新,然后 inf 循环,但我不确定我是如何导致这个问题的。componentDidUpdate() {        if (this.state.score === 4) {            this.setState({ size: 9 });        } else if (this.state.score === 9) {            this.setState({ size: 16 });        }    }
查看完整描述

2 回答

?
哔哔one

TA贡献1854条经验 获得超8个赞

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


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>


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


查看完整回答
反对 回复 2022-10-08
?
泛舟湖上清波郎朗

TA贡献1818条经验 获得超3个赞

评论中的答案。将代码移动到 isMatch 中或将其保留在 componentDidUpdate 中,但还要调整代码以检查 prevState



查看完整回答
反对 回复 2022-10-08
  • 2 回答
  • 0 关注
  • 159 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号