2017-10-24 1 views
1

나는 Conway의 라이프 게임을 시뮬레이션하는 React의 앱을 가지고 있습니다. 그것은 0.01 초마다 setInterval() 함수로 지정된 새로운 요소를 업데이트하는 간단한 2D 배열로 구성됩니다. 그러나 처음 5 초 동안 원활하게 실행 한 후에는 0.5 초마다 업데이트 될 때까지 상당히 느려집니다. 나는 앱이 너무 느려지 게하는 원인을 찾으려고 할 때 잃어 버렸습니다. 는 createGrid() 함수에서 보듯심각한 지연을 겪고있는 리얼 웹 앱

var React = require('react'); 
var createReactClass = require('create-react-class'); 
var ReactDOM = require('react-dom'); 
var Button = require('react-bootstrap').Button; 
var Row = require('react-bootstrap').Row; 
var Col = require('react-bootstrap').Col; 
var FontAwesome = require('react-fontawesome'); 

// components 
var Cell = require('./Cell.jsx'); 

var Grid = createReactClass({ 
    getInitialState: function() { 
    return { 
     matrix: [], 
     generations: 0, 
     neighborCells: [[0, 1], [1, 0], [-1, 0], [0, -1], [-1, -1], [1, 1], [-1, 1], [1, -1]] 
    }; 
    }, 

    componentWillMount: function() { 
    this.freshGrid(); 
    }, 

    freshGrid: function() { 
    var matrix = []; 
    var dim = this.props.dim; 

    var Cell = function() { 
     this.neighborsCount = 0; 
     this.isAlive = false; 
    } 

    var counter = 0; 
    for (var i = 0; i < dim; i++) { 
     var row = []; 
     for (var j = 0; j < dim; j++) { 
     counter++; 
     var cell = new Cell(); 
     row.push(cell); 

     if (counter%2 == 0) { 
      cell.isAlive = true; 
     } 
     } 
     matrix.push(row); 
    } 

    this.setState({matrix: matrix}, function() { 
     this.createGrid(); 
    }); 
    }, 

    createGrid: function() { 
    this.interval = setInterval(function() { 
     this.countNeighbours(); 
     this.updateCells(); 
     this.forceUpdate(); 
     this.clearNeighborsCount(); 
    }.bind(this), 10); 
    }, 

    countNeighbours: function() { 
    var dim = this.props.dim; 

    for (var i = 0; i < dim; i++) { 
     for (var j = 0; j < dim; j++) { 
     this.countNeighboursCell(i, j); 
     } 
    } 
    }, 

    countNeighboursCell: function(row, col) { 
    var neighborCells = this.state.neighborCells; 
    var cell = this.state.matrix[row][col]; 

    for (var i = 0; i < neighborCells.length; i++) { 
     var neighborPos = neighborCells[i]; 
     var x = row + neighborPos[0]; 
     var y = col + neighborPos[1]; 

     if (this.isWithinGrid(x, y)) { 
     var neighbor = this.state.matrix[x][y]; 
     if (neighbor.isAlive) { 
      cell.neighborsCount++; 
     } 
     } 
    } 
    }, 

    isWithinGrid: function(row, col) { 
    var dim = this.props.dim; 

    if (row >= 0 && col >= 0 && row < dim && col < dim) { 
     return true; 
    } 
    return false; 
    }, 

    updateCells: function() { 
    var dim = this.props.dim; 

    for (var i = 0; i < dim; i++) { 
     for (var j = 0; j < dim; j++) { 
     var currentCell = this.state.matrix[i][j]; 

     if (currentCell.isAlive && (currentCell.neighborsCount == 2 || currentCell.neighborsCount == 3)) { 
      currentCell.isAlive = true; 
     } else if (!currentCell.isAlive && currentCell.neighborsCount == 3) { 
      currentCell.isAlive = true; 
     } else { 
      currentCell.isAlive = false; 
     } 
     } 
    } 
    }, 

    clearNeighborsCount: function() { 
    var dim = this.props.dim; 

    for (var i = 0; i < dim; i++) { 
     for (var j = 0; j < dim; j++) { 
     this.state.matrix[i][j].neighborsCount = 0; 
     } 
    } 
    }, 

    togglePause: function(e) { 
    if (e.target.innerHTML === 'Pause') { 
     clearInterval(this.interval); 
     e.target.innerHTML = 'Play'; 
    } else { 
     e.target.innerHTML = 'Pause'; 
     this.createGrid(); 
    } 
    }, 

    reset: function() { 
    this.freshGrid(); 
    }, 

    render: function() { 
    var dim = this.props.dim; 

    var cells = []; 
    for (var i = 0; i < dim; i++) { 
     var row = []; 
     for (var j = 0; j < dim; j++) { 
     row.push(<Cell key={i+j} row={i} col={j} dim={10} isAlive={this.state.matrix[i][j].isAlive} />) 
     } 
     cells.push(row); 
    }; 

    var gridStyle = { 
      width: this.props.dim * 10, 
      height: this.props.dim * 10, 
      background: "#FAFAFA", 
      margin: "0 auto", 
      WebKitBoxShadow: "0 0 5px rgba(0, 0, 0, 1)", 
      MozBoxShadow: "0 0 5px rgba(0, 0, 0, 1)", 
      boxShadow: "0 0 5px rgba(0, 0, 0, 1)" 
     }; 

    return (
     <Row> 
     <Col xs={12} md={2}> 
      <Button onClick={this.togglePause} bsStyle="warning">Pause</Button> 
      {/* <Button onClick={this.reset} bsStyle="danger">Reset</Button> */} 
     </Col> 

     <Col xs={12} md={10}> 
      <div style={gridStyle}> 
      {cells} 
      </div> 
     </Col> 
    </Row> 
    ); 
    } 
}); 

module.exports = Grid; 

우리는 새로운 요소 그리드 매 0.01 초를 업데이트

여기 2D 배열을 렌더링하는 전체 그리드 구성 요소이다. 그러나 시간이 지나면 상당히 느려집니다. 나는 그것이 너무 심하게 지연되는 원인을 찾고있다. 모든 브라우저와 모바일에서도 발생합니다.

편집 :

요청으로

, 여기 Cell.jsx

var React = require('react'); 
var createReactClass = require('create-react-class'); 

var Cell = createReactClass({ 

    render: function() { 
    var dim = this.props.dim; 

    var cellStyle = { 
      width: dim, 
      height: dim, 
      dislay: "inline-block", 
      float: "left", 
      border: "1px solid #000", 
      background: this.props.isAlive ? "#FFF" : "#151515" 
     }; 

    return(
     <div className="cell" onClick={this.clicked} style={cellStyle}></div> 
    ); 
    } 
}); 

module.exports = Cell; 

편집 2 :

You can render the grid with this App component 

var React = require('react'); 
var createReactClass = require('create-react-class'); 

// components 
var Grid = require('./Grid.jsx'); 

var App = createReactClass({ 
    render: function(){ 
    return(
     <Grid dim={51}/> 
    ); 
    } 
}); 

module.exports = App; 
+0

왜 'this.forceUpdate();'를 실행하고 있습니까? 나는 뭔가를 놓칠지도 모르지만 당신은 당신의 간격에서 많은 계산을하고 있습니다. 그러나 나는 당신이 그 계산을 어떻게 그리고 어디에서 사용하고 있는지를 볼 수 없습니다. – bennygenel

+1

'Cell.jsx'하십시오. – hazardous

+0

프로필러를 실행 해 보셨습니까? Google 크롬 - F12 - 성능 탭 – c69

답변

0

몇 가지 팁을 기존의 코드를 기반으로 -

  1. 타이머를 사용하지 마십시오. 타이머 대신 매트릭스를 한 번 렌더링 한 다음 componentDidUpdate으로 매트릭스를 업데이트하는 함수를 호출 할 수 있습니다. 이 함수에서는 setState을 사용하여 새 행렬을 다시 상태로 저장합니다. 그러면 새 상태에 대해 render이 트리거됩니다. 이것은 영원히 계속 될 것이지만 다중 실행을 쌓지는 않을 것입니다.

  2. 불변의 상태를 사용하십시오. 현재 코드는 state.matrix을 직접 참조하고 cells을 업데이트합니다. 이것은 렌더링을 다시하지 않고 상태를 변경합니다. 이를 위해 Object.assign을 사용하거나 ImmutableJS를 사용할 수 있습니다. >

    계산 행렬을 렌더링>

    는 현재 행렬을 받아 다음 행렬을 반환 calculateMatrix 말을하는 함수를 쓰기 반복 -

  3. 재구성이 코드는 다음과 같은 방식으로이 작업을 수행 할 수 있습니다. updateMatrix 다른 함수를 작성하여 현재 행렬에 calculateMatrix을 호출 한 다음 setState을 호출하여 새 행렬을 상태로 저장합니다. updateMatrixcomponentDidMountcomponentDidUpdate에 호출하십시오. 이렇게하면 calculate> render> 반복주기 광고 무한이 시작됩니다.

관련 문제