【问题标题】:How could I reset the state of my component according to changes in the parent component?如何根据父组件的更改重置组件的状态?
【发布时间】:2020-02-16 14:30:30
【问题描述】:

为了实践我在 React 中学到的东西,我正在尝试在 React 中制作某种 QCM。

the architecture of the components of the application

这张图片描述了我的应用程序组件的架构。

App 组件包含主要状态和改变状态的功能。

组件板包含 4 个建议的答案和一些实用功能,用于打乱它从 App 组件收到的答案。

所以用户可以点击包含答案的按钮。如果答案错误,按钮变为红色。如果答案正确,则按钮变为绿色,App 组件的状态更改为将正确答案的数量增加 1。此外,由于状态的另一个元素,显示了“按钮下一步”组件。它允许更改问题和答案。当新答案出现时,我希望答案按钮变为初始颜色。

问题是:如何通过单击“按钮下一步”组件来更改答案组件的状态?

所以,我已经将答案按钮的颜色存储在它的状态中,并且它的更新是通过调用 App 组件中的一个函数的 onClick 事件完成的。

我想过当好答案的数量增加一时将答案按钮的颜色更改为其初始颜色,但结果似乎很随机。

当我在网上搜索答案时,我只发现了这种问题,但是元素处于相同的 react 组件中并且使用相同的状态。

有人有想法吗?

PS:目前,我尝试在没有 redux 和 hooks 的情况下做一些事情。当我只用基本的反应就能成功时,我会使用钩子。

import React from 'react';
import './App.css';

const datas = [
  {
    id:1,
    question: 1,
    answer: 11
  },
  {
    id:2,
    question: 2,
    answer: 22
  },
  {
    id:3,
    question: 3,
    answer: 33
  },
  {
    id:4,
    question: 4,
    answer: 44
  },
  {
    id:5,
    question: 5,
    answer: 55
  },
  {
    id:6,
    question: 6,
    answer: 66
  },
  {
    id:7,
    question: 7,
    answer: 77
  },
  {
    id:8,
    question: 8,
    answer: 88
  },
  {
    id:9,
    question: 9,
    answer: 99
  }
]

class App extends React.Component {
  constructor(props){
    super(props)
    this.state = {
      guesses: 0,
      won: false,
      buttonClicked: false
    }
  }

  getId(datas){
    const tabIdLetters = []
    datas.map((data, index) =>
      (tabIdLetters.push(data.id))
    )
    return tabIdLetters
  }  //return an array with the ID elements of the datas


  getRandom(arr, n) {
    var result = new Array(n),
        len = arr.length,
        taken = new Array(len);
    if (n > len)
        throw new RangeError("getRandom: more elements taken than available");

    while (n--) {
        var x = Math.floor(Math.random() * len);
        result[n] = arr[x in taken ? taken[x] : x];
        taken[x] = --len in taken ? taken[len] : len;
    }

    return result;
  } //get n random elements from a tab

  getOneRandom(arr) {
    var result,
        len = arr.length;
        var x = Math.floor(Math.random() * len);
        result = arr[x]
    return result;
  }  //get one random element from a tab

  handleWon(){
    this.setState({
      won: true
    })
  }

  handleButtonNext(){
    const newGuesses = this.state.guesses + 1
    this.setState({ 
      guesses: newGuesses,
      won: false,
      buttonClicked: true
    })
  }

  render(){
    const lettersSelected = this.getRandom(this.getId(this.props.datas), 4) //the 4 answers which will be displayed
    const letterQueried = this.getOneRandom(lettersSelected) //among these 4 letters, one will be the one being asked

    return (
      <div className="App">
        <Board datas={datas} className="board" lettersSelected={lettersSelected} letterQueried={letterQueried} app={this} />
        <LetterQuerried lettersSelected={lettersSelected} letterQueried={letterQueried} app={this} />
        {this.state.won && <ButtonNext app={this} style={{display:this.state.visible}} />}
      </div>
    )
  }
}

export default App;

//============== component in which there are the 4 answers buttons ==================

class Board extends React.Component{
  constructor(props){
    super(props)
  }

  shuffle(array) {
    var currentIndex = array.length, temporaryValue, randomIndex;

    // While there remain elements to shuffle...
    while (0 !== currentIndex) {

      // Pick a remaining element...
      randomIndex = Math.floor(Math.random() * currentIndex);
      currentIndex -= 1;

      // And swap it with the current element.
      temporaryValue = array[currentIndex];
      array[currentIndex] = array[randomIndex];
      array[randomIndex] = temporaryValue;
    }

    return array;
  }    //shuffle the array to display the answer buttons in a random order

  //The component should re render only if the button next has been clicked
  shouldComponentUpdate(nextProps, nextState){
    if(nextProps.app.state.buttonClicked == false){
      return false
    }
    else{
      return true
    }
  }

  render(){
    const datas = this.shuffle(this.props.datas)
    return(
      <div>
        {datas.map((data, index) => 
          (this.props.lettersSelected.includes(data.id) && <LetterProposed id={data.id} data={data.answer} key={index} letterQueried={this.props.letterQueried} app={this.props.app} board={this} />)
        )}
      </div>
    )
  }
}

//=========================== answer button component ===================================

class LetterProposed extends React.Component{
  constructor(props){
    super(props)
    this.state = {
      bgColor: 'gray'
    }
  }

  handlerClick(e){
    this.props.app.state.buttonClicked = false

    if(e.target.id == this.props.letterQueried){  //correct answer
      this.setState({
        bgColor: 'green'
      })
      this.props.app.handleWon()
    }
    else if(e.target.id != this.props.letterQueried){ //wrong answer
      this.setState({
        bgColor: 'red' 
      })
    }
  }

  shouldComponentUpdate(nextProps){
    if(this.props.app.state.guesses !== nextProps.app.state.guesses){
      return false
    }
    else{
      return true
    }
  }

  render(){
    return(
    <button id={this.props.id} onClick={this.handlerClick.bind(this)} style={{backgroundColor:this.state.bgColor}}>{this.props.data}</button>
    )
  }
}

//================= Question component ========================

class LetterQuerried extends React.Component{
  constructor(props){
    super(props)
  }

  shouldComponentUpdate(nextProps, nextState){
    if(nextProps.app.state.buttonClicked == false){
      return false
    }
    else{
      return true
    }
  }

  render(){
    return(
      <p>{this.props.letterQueried}</p>
    )
  }
}

//==================== Button next component ==============================

class ButtonNext extends React.Component{

  constructor(props){
    super(props)
    this.state = {
      visible: 'block'
    }
  }

  handlerClick(){
    this.props.app.handleButtonNext()
  }

  render(){
    return(
      <button onClick={this.handlerClick.bind(this)}>Suivant</button>
    )
  }
}

【问题讨论】:

  • 你能提供到目前为止你尝试过的代码吗?这将有助于为您的问题提供清晰和更好的解决方案。另请参阅有关如何在论坛上提问的部分
  • @chitova263 我已经编辑了我的消息以添加代码。我只隐藏了实用程序功能使其更短

标签: reactjs


【解决方案1】:

最简单的方法是将子状态放入父组件并在那里进行管理。

或者您可以将父状态作为参数传递给子状态。 在孩子中,我们应用这个:

componentDidUpdate(prevProps) {   
    if (this.props.parentStateFromProps !== prevProps.parentStateFromProps) {
    this.setState(INITIAL_STATE);
    }
}

带钩子:

React.useEffect(() => {
    setState(INITIAL_STATE);
}, [parentStateFromProps]);

【讨论】:

  • 谢谢,但是还是有同样的问题:当我点击按钮再次播放时,并不是所有的答案按钮都会变回原来的颜色。并且不是始终处于初始颜色的按钮并不总是同一个按钮。我真的不明白实际发生了什么:(
猜你喜欢
  • 2016-07-19
  • 2018-10-18
  • 2017-11-27
  • 2016-12-21
  • 1970-01-01
  • 2018-02-25
  • 2021-03-27
  • 1970-01-01
相关资源
最近更新 更多