튜토리얼(Tutorial) - 10
앞선 포스팅에서 틱택토 그리드에 버튼을 클릭할 때 마다 히스토리를 저장했다.
이렇게 저장한 히스토리를 호출하여 움직임으로 보여주고, 해당 시점으로 이동하는 기능을 추가해보자
움직임 보여주기
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | render() { const history = this.state.history; const current = history[history.length - 1]; const winner = calculateWinner(current.squares); const moves = history.map((step, move) => { const desc = move ? 'Move #' + move : 'Game start'; return ( <li> <a href="#" onClick={() => this.jumpTo(move)}>{desc}</a> </li> ); }); let status; if (winner) { status = 'Winner: ' + winner; } else { status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O'); } return ( <div className="game"> <div className="game-board"> <Board squares={current.squares} onClick={(i) => this.handleClick(i)} /> </div> <div className="game-info"> <div>{status}</div> <ol>{moves}</ol> </div> </div> ); } | cs |
지금까지 게임 중에 만들어진 동작들을 보여주는 기능을 추가해보자.
리액트 엘리먼트는 자바스크립트 일급객체와 동일하게 취급되므로 값을 저장하거나 전달할 수 있다.
리액트에서는 여러 항목을 랜더링 하기위해 리액트 엘리먼트의 배열을 전달 한다.
배열을 만드는 가장 일반적인 방법은 데이터 배열을 매핑(map 메소드를 사용해서)하는 것이다.
Game의 render메소드에서 이를 구현할 수 있다.
히스토리의 각 단계 마다 아무것도 없는 <a>태그가 포함된 <li>리스트를 만들고
곧 구현한 클릭 핸들러를 넣어준다.
시점 이동 구현
1 2 3 4 5 6 7 8 9 10 | const moves = history.map((step, move) => { const desc = move ? 'Move #' + move : 'Game start'; return ( <li key={move}> <a href="#" onClick={() => this.jumpTo(move)}>{desc}</a> </li> ); }); | cs |
히스토리의 각 단계마다 고유의 구분되어지는 key값을 설정한다.
바로 이동 되어진 횟수이다.
따라서 <li> 태그 안에 key값으로 {move}값을 넣어준다
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | class Game extends React.Component { constructor() { super(); this.state = { history: [{ squares: Array(9).fill(null), }], stepNumber: 0, xIsNext: true, }; } jumpTo(step) { this.setState({ stepNumber: step, xIsNext: (step % 2) ? false : true, }); } | cs |
우선 constructor에 stepNumber라는 새로운 state를 추가해준다.
이 state는 현재 보고 있는 step이 어디인지 알려주는 역할을 한다.
또한 jumpTo를 구현하지 않았으므로 Game 컴포넌트 안에 구현해 준다.
이때 중요한 것은 이전으로 돌아가기 때문에 X/O에 대한 순서도 재설정할 필요가 있는데,
스텝이 짝수이면 xIsNext를 true로 설정한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | handleClick(i) { const history = this.state.history.slice(0, this.state.stepNumber + 1); const current = history[history.length - 1]; const squares = current.squares.slice(); if (calculateWinner(squares) || squares[i]) { return; } squares[i] = this.state.xIsNext ? 'X' : 'O'; this.setState({ history: history.concat([{ squares: squares }]), stepNumber: history.length, xIsNext: !this.state.xIsNext, }); } | cs |
그리고 클릭이 일어날 때마다 stepNumber를 업데이트 시켜야한다.
또한 랜더링은 이러한 StepNumber를 기준으로 이루어진다.
이를 위해서 handleClick 메소드를 위와 같이 수정해주도록 하자
1 2 3 4 5 6 | render() { const history = this.state.history; const current = history[this.state.stepNumber]; const winner = calculateWinner(current.squares); // the rest has not changed | cs |
'개발' 카테고리의 다른 글
[Raspberry] 정적 IP 할당 (0) | 2017.06.11 |
---|---|
[Raspberry] 맥에 라즈비안 OS 설치 (0) | 2017.06.11 |
[ReactJS] 튜토리얼(Tutorial) - 9 (0) | 2017.06.11 |
[ReactJS] 튜토리얼(Tutorial) - 8 (0) | 2017.06.10 |
[ReactJS] 튜토리얼(Tutorial) - 7 (0) | 2017.06.10 |
댓글