2016-11-25 117 views
0

我正在使用地图函数从一个对象数组创建一个游戏板并在点击时调用setState来使游戏发生。我可以成功地更新状态,但只有在执行不同的操作之后,视图才会更新。我猜测问题在于map函数如何将道具传递给子元素(Cell),但我无法弄清楚我做错了什么。reactjs - 改变状态不会重新渲染组件

var board = []; 
var width = 50; 
var height = 30; 
var size = width * height; 


for (var i=1; i<=size; i++) { 
    board[i] = {id: i, status: 'dead'}; 
} 

var Cell = React.createClass({ 
    turn: function() { 
    this.props.turn(this.props.id); 
    }, 

    render: function() { 
    return <div id={this.props.id} className={this.props.status} onClick={this.turn}></div> 
    } 
}); 

var GameBoard = React.createClass({ 
    getInitialState: function() {  
    return { 
     board: board 
    }; 
    }, 

    handleClick: function(id) { 
    var newBoard = this.state.board; 
    newBoard[id] = {id: id, status: 'alive'}; 
    this.setState({board: newBoard}); 
    }, 

    move: function() { 
    var board = this.state.board; 
    var newBoard = board; 
    for (var j=1;j<=board.length;j++) { 
     if (board[j].status == 'alive') { 
     newBoard[j-1] = {id: j-1, status: 'alive'}; 
     newBoard[j] = {id: j, status: 'dead'}; 
     } 
    } 
    this.setState({board: newBoard}); 
    }, 

    render: function() { 
    var squares = this.state.board.map(function(item){ 
     return <Cell id={item.id} status={item.status} turn={this.handleClick}/> 
    }.bind(this)); 
    return (
     <div> 
     <h1>Game of Life</h1> 
     <button className="btn btn-default" onClick={this.move}>Run</button> 
     <div className='boardContainer'>{squares}</div> 
     </div> 
    ); 
    } 
}); 

ReactDOM.render(<GameBoard/>,document.getElementById('app'));  

http://codepen.io/Theeeus/pen/YpQzPO?editors=0010

回答

0

循环在你move功能是关闭的情况的一个,所以它达到符合setState之前抛出一个错误。该方法的前两行简单地在变量newBoard中分配对this.state.board的引用。因此,您正在“更新”您的状态,但与setState不正确。这就是为什么董事会更新您的下一次点击,这在​​调用setState

1)你应该修改状态,而不是状态本身

2)修复的off-by-一个错误的for循环的深层副本

var board = this.state.board; 
var newBoard = board; // Note, this is a reference to this.state.board. That's bad! 
for (var j=1; j<=board.length - 1; j++) { // note, -1 
    ... 
} 
+0

谢谢山姆!更改循环已经修复了错误,但我不知道将状态分配给变量仍然会影响状态。我会修改该部分以避免将来出现问题。 –

0

请使用

if(var i = 0;i < arr.length;i++) 

,而不是

if(var i = 1;i<=arr.length;i++){} 

在你的问题中,当你的移动函数中的j等于board.length时,它会产生错误。 在你的代码中改变你的两个if循环。 我希望我能帮上忙。

var board = []; 
 
var width = 2; 
 
var height = 3; 
 
var size = width * height; 
 

 

 
for (var i=0; i < size; i++) { 
 
    board[i] = {id: i, status: 'dead'}; 
 
} 
 

 
var Cell = React.createClass({ 
 
    turn: function() { 
 
    this.props.turn(this.props.id); 
 
    }, 
 

 
    render: function() { 
 
    return <div id={this.props.id} className={this.props.status} onClick={this.turn}></div> 
 
    } 
 
}); 
 
var GameBoard = React.createClass({ 
 
    getInitialState: function() {  
 
    return { 
 
     board: board 
 
    }; 
 
    }, 
 

 
    handleClick: function(id) { 
 
    var newBoard = this.state.board; 
 
    newBoard[id] = {id: id, status: 'alive'}; 
 
    this.setState({board: newBoard}); 
 
    }, 
 

 
    move: function() { 
 
    var board = this.state.board; 
 
    var newBoard = board; 
 
    for (var j=0;j < board.length;j++) { 
 
     if (board[j].status == 'alive') { 
 
     newBoard[j-1] = {id: j-1, status: 'alive'}; 
 
     newBoard[j] = {id: j, status: 'dead'}; 
 
     } 
 
    } 
 
    this.setState({board: newBoard}); 
 
    }, 
 

 
    render: function() { 
 
    var squares = this.state.board.map(function(item){ 
 
     return <Cell key = {item.id} fuck={item.id} id={item.id} status={item.status} turn={this.handleClick}/> 
 
    }.bind(this)); 
 

 
    return (
 
     <div> 
 
     <h1>Game of Life</h1> 
 
     <button className="btn btn-default" onClick={this.move}>Run</button> 
 
     <div className='boardContainer'>{squares}</div> 
 
     </div> 
 
    ); 
 
    } 
 
}); 
 

 
ReactDOM.render(<GameBoard/>,document.getElementById('app'));
.dead{ 
 

 
width:10px;height:10px;border:1px solid red;margin:3px; 
 

 
     } 
 
     .alive{ 
 
     border:1px solid green;margin:3px;width:10px;height:10px; 
 
     }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script> 
 
<div id="app"></div>

0

你变异this.stateReact docs指定这是否定的。在GameBoard组件内,我已经重写你的handleClick()move()功能看起来更像是这样的:

handleClick: function(id) { 
    this.setState({ 
    ...this.state, 
    board: [ 
     ...this.state.board.slice(0, id), 
     { 
     id, 
     status: 'alive' 
     }, 
     ...this.state.board.slice(id + 1) 
    ] 
    }); 
}, 

move: function() { 
    this.setState({ 
    ...this.state, 
    board: this.state.board.map((place, id, board) => { 
     const nextPlace = board[id + 1]; 
     if (nextPlace.status === 'alive') { 
     return { 
      ...place, 
      status: 'alive' 
     }; 
     } else if (place.status === 'alive') { 
     return { 
      ...place, 
      status: 'dead' 
     }; 
     } 
     return place; 
    }) 
    }); 
}, 

注:这些功能使用一些新的JavaScript功能,如传播运营商(...place)和箭头的功能。当您尝试运行此代码时,这些功能可能会导致语法错误。

+0

我对扩散算子不熟悉,但我会通读文档并试一试。谢谢! –