将 onChange 绑定值反应到父级数组

react onChange bind value to array in parent

我是 React js 的新手,正在尝试构建一个简单的魔方游戏。我能够填充初始值。我一直在想办法让用户输入反映在父组件中。即在 Board class 的 handleChange(i) 方法中将空 Square 中输入的新值设置为 squares[i]。

class Square extends React.Component {

  render()
  {
    return (
      <input type="text" className="square" value={this.props.value} onChange={this.handleChange}>
      </input>
    );
  }
}

/* Defines the Main Game Board */
class Board extends React.Component {
  constructor(props) {
    super(props);

    this.handleChange = this.handleChange.bind(this);

    /*Array to store Random numbers*/
    const randArray = [];

    for(var i = 0; i < 3; i++) 
    {
      var numberIsInArray = false;
      var rand = generateRandomNumb(1, 9);
      for(var j = 0; j < randArray.length; j++){
          if(rand === randArray[j]) {
              numberIsInArray = true;
              i--;
          }
      }
      if(!numberIsInArray){
         randArray.push(rand);
      }
    }

    /*function to generate Random Numbers*/
    function generateRandomNumb(min, max) 
    {
      return Math.floor(Math.random() * (max - min) + min);
    }

    function check(grid_val, arr)
    {
      if (arr[0] === grid_val || arr[1] === grid_val || arr[2] === grid_val)
        return grid_val;
    }

    this.state = {
      squares: Array(
         (4,check(4,randArray))
        ,(9,check(9,randArray))
        ,(2,check(2,randArray))
        ,(3,check(3,randArray))
        ,(5,check(5,randArray))
        ,(7,check(7,randArray))
        ,(8,check(8,randArray))
        ,(1,check(1,randArray))
        ,(6,check(6,randArray))
        )
    };
  }

  handleChange(i) {
    const squares = this.state.squares.slice();
    squares[i] = '';
    //this.setState({squares: squares});
  }

  renderSquare(i) {
    return (
      <Square
        value={this.state.squares[i]}
        onChange={this.handleChange(i)}
      />
    );
  }

  render() {

    const status = this.state.squares;    

    return (
      <div>
        <div className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <h2>Sudoku React</h2>
        </div>
        <div className="status">{status}</div>
        <div className="board-row">
          {this.renderSquare(0)}
          {this.renderSquare(1)}
          {this.renderSquare(2)}
        </div>
        <div className="board-row">
          {this.renderSquare(3)}
          {this.renderSquare(4)}
          {this.renderSquare(5)}
        </div>
        <div className="board-row">
          {this.renderSquare(6)}
          {this.renderSquare(7)}
          {this.renderSquare(8)}
        </div>
        <div>
          <button onClick={() => window.location.reload()}>Start New Game</button>
        </div>
      </div>
    );
  }
}
export default Board;

这里有一些问题。

第 1 期

当您创建一个 <Square /> 组件时,您将传递名为 valueonChange 的道具。但是在 Square 组件中,您正试图使用​​ this.handleChange 作为 onChange 处理程序。

this.handleChange 确实作为 Square 的 属性 存在。相反,您应该使用 Board 父级传递给它的 this.props.onChange

class Square extends React.Component {
  // handleChange () {
  // this is the none existant function referred to in the render function 
  // Instead: use this.props.onChange passed by the parent <Board /> 
  // }

  render()
  {
    return (
      <input type="text" className="square" value={this.props.value} onChange={this.handleChange}>
      </input>
    );
  }
}

这仍然无法工作,因为...

第 2 期

输入的 onChange 方法应该是一个函数。

问题 #1 解决后,Square 的 this.props.onChange 将变为 undefined。 这是因为 handleChange 在我们作为 prop 传递时被调用(调用)。由于 handleChange 没有 return 值,我们传递 undefined.

renderSquare(i) {
  return (
    <Square
      value={this.state.squares[i]}
      onChange={this.handleChange(i)} // handleChange is being invoked! Note ()
    />
  );
}

修复此问题所需的最少编辑是 handleChange return 一个函数,它接受我们用来更新状态的事件。

handleChange (i) {
  // Return ES6 bound function to maintain `this`
  return (e) => {
    const squares = this.state.squares.slice();
    squares[i] = e.target.value; // The value of the input
    this.setState({squares: squares});
  };
}

P.s。一些额外的一般性评论; renderSquare 应该在构造函数中绑定到 this 就像 handleChange

this.renderSquare = this.renderSquare.bind(this);
this.handleChange = this.handleChange.bind(this);

我还会将 generateRandomNumbcheck 移出 <Board /> 的构造函数,并将它们放在示例代码的最顶部,在任何 class 之外.

也把randArray代移到一个函数里,也移到最上面

function generateRandArray () {
  var randArray = [];
  for(var i = 0; i < 3; i++) 
  {
    var numberIsInArray = false;
    var rand = generateRandomNumb(1, 9);
    for(var j = 0; j < randArray.length; j++){
      if(rand === randArray[j]) {
        numberIsInArray = true;
        i--;
      }
    }
    if(!numberIsInArray){
      randArray.push(rand);
    }
  }
  return randArray;
}

并且在<Board />

的构造函数中
const randArray = generateRandArray();