简体   繁体   中英

Changing state in a function from a button click does not trigger a rerender in React.js

I've got a matrix of cells - small rectangles - in React and a button. On a button click, I want to clear all the cells. First, I create lots of empty cells with some non-empty ones and pass it down a CellGrid component, which renders all the cells just fine. I linked the button onClick to a function, which changes the state (this.state.cells), but it does not trigger a rerender in the child component (CellGrid).

class Playfield extends React.Component {
  constructor(props){
    super(props);
    this.clearButtonClick = this.clearButtonClick.bind(this);
  }

  componentWillMount(){
    var arr = [];
    for (var i=0; i < 64*64; ++i){ // all empty cells at first
      arr.push({id:i, status: "empty"}); 
    }
    for (var i=0; i < startCells.length; ++i){ // mark special cells
      var newIndex = startCells[i].x + 64*startCells[i].y;
      arr[newIndex].status = "alive";
    }
    this.setState({ // change state
      cells: arr
    });
  }

  clearButtonClick(){
    console.log("clear")
    var newArr = [];
    for (var i=0; i < this.state.cells.length; ++i){ // all empty cells again
      newArr.push({id:i, status: "empty"});
    }

    this.setState({ // change state --- NOT UPDATING THE RENDER
      cells: newArr
    });

  }

  render(){
    return (
      <div className="Playfield">
        <CellGrid grid_cells={this.state.cells}/>
        <Button onClick={this.clearButtonClick}>CLEAR</Button>        
      </div>
    );
  }
}

And the CellGrid looks like this.

class CellGrid extends React.Component {
  constructor(props){
    super(props);
    this.renderCells = this.renderCells.bind(this);
  }

  renderCells(){
    return (this.props.grid_cells.map(function(cell){
      return (        
        <Cell id={cell.id} status={cell.status}/>);
    }));
  }

  render(){
    return (
      <div className="CellGrid">
        {this.renderCells()}        
      </div>
    );
  }
}

Anyone got a hint? Related questions all changed the state the wrong way.

It's actually working; you can put a console log in the render method of CellGrid to see that render is triggered when you click clear. The problem actually lies within your <Cell> component.

<Cell> seems to only use status from props on initial mounting where it copies status from props into it's own internal state and then rendering of the cell comes from this.state.status instead of this.props.status . I imagine you did it this way to use onClick to toggle the cells. What you might want to do is get rid of the local state in <Cell> and always render it using this.props.status and just also pass an onClick through from <Playfield> to <CellGrid> and then from <CellGrid> to each <Cell> .

Also, make sure you're using the key= property any time you are rendering components from an array (like in <CellGrid> ).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM