튜토리얼(Tutorial) - 6
이제 우리는 Square를 클릭 했을 때 일어나는 이벤트를 변경해야한다.
Board 컴포넌트는 Square의 상태를 배열로써 저장하고 있다.
즉, Square가 Board가 가지고 있는 state 값을 업데이트 할 수 있는 방법을 찾아야한다는 것이다.
컴포넌트의 state는 비공개로 설정되었으므로
Board에 있는 Square의 상태를 Square에서 직접 접근하여 업데이트 할 수 없다.
1 2 3 4 5 6 7 8 | renderSquare(i) { return ( <Square value={this.state.squares[i]} onClick={() => this.handleClick(i)} /> ); } | cs |
이 때 일반적으로 사용되는 패턴은 Board에서 Square로 함수를 전달하는 것이다.
Board 함수 내부의 renderSquare 함수를 위와 같이 변경해준다.
위의 코드에서 주목할 점은 가독성을 위해 코드를 여러줄로 분리한 것이다.
그리고 return 되는 코드를 괄호로 감싸고 세미콜론으로 구분했다.
이제 우리는 Board에서 Square로 value와 onClick이라는 2개의 props를 전달하게 된다.
onClick은 Square에서 호출할 수 있는 함수이다.
1 2 3 4 5 6 7 8 9 | class Square extends React.Component { render() { return ( <button className="square" onClick={() => this.props.onClick()}> {this.props.value} </button> ); } } | cs |
상위 컴포넌트에서 전달되는 props 값이 변경됨에 따라 하위 컴포넌트인 Square의 값도 달라져야한다.
따라서 Square도 다음과 같이 변경해준다.
- render 메소드의 this.state.value를 this.props.value로 변경한다.
- render 메소드의 this.setState()를 this.props.onClick()으로 변경한다.
- Square의 construct를 삭제하여 더 이상 아무런 state도 가지지 않게 해준다.
모든 코드작성이 완료되면 위와 같은 코드가 될것이다.
이제 Square를 클릭하면 Board에서 전달된 onClick() 메소드가 호출 된다.
여기에서 일어나는 일을 요약하면 다음과 같다.
1. 기본적으로 내장된 <button>의 onClick() prop은 React에게 클릭 이벤트 리스너를 설정하도록 지시한다.
2. 버튼이 클릭되면, React는 Square의 render() 메소드에 정의된 onClick 이벤트 핸들러를 호출한다.
3. 이벤트 핸들러는 this.props.onClick()를 호출한다. Square의 props는 Board에 의해 지정되었다.
4. Board는 onClick() = {()=>this.handleClick(i)}를 Square로 전달했으므로
호출될 때 보드에서 this.handleClick(i)을 실행한다.
5. 아직 this.handleClick(i)를 작성하지 않았으므로 에러가 발생한다.
onClick은 <Button> 태그에서는 클릭 이벤트를 등록하는 특별한 의미를 가지지만
Square의 onClick이나 Borad의 handleClick은 조금 다른 의미를 가진다.
리액트에서는 일반적으로 handler prop에 대해 on*,
이 prop에 대한 구현 함수는 handle*라는 이름을 붙이는 규칙이 있다.
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 39 40 41 42 43 44 45 46 47 48 | class Board extends React.Component { constructor() { super(); this.state = { squares: Array(9).fill(null), }; } handleClick(i) { const squares = this.state.squares.slice(); squares[i] = 'X'; this.setState({squares: squares}); } renderSquare(i) { return ( <Square value={this.state.squares[i]} onClick={() => this.handleClick(i)} /> ); } render() { const status = 'Next player: X'; return ( <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> ); } } | cs |
이제 handleClick을 만들어 줘야하는데, 위의 코드 예제 처럼 handleClick을 작성해준다.
handleClick 메소드는 constructor와 renderSquare 사이에 있다.
handleClick에서는 .slice()를 호출하여, 기존의 배열을 변경하는 대신 배열을 복사해준다.
이는 불변성(Immutation)을 유지하기 위함인데, 여기에 대해서는 추후에 설명하도록 하겠다.
이제 Square를 클릭하면 값이 채워지는데,
상태값은 Square 컴포넌트가 아닌 Board에 저장되므로 게임을 계속 진행할수 있다.
그리고 Board의 상태가 변경될 때 마다 Square의 컴포넌트가 자동으로 랜더링 된다.
한번 더 강조하자면 Square는 상태를 더이상 가지지 않는다.
Square는 상위 컴포넌트로 부터 value 값을 얻고, 클릭 되었을 때 부모에게 알린다.
이와 같은 컴포넌트를 제어 컴포넌트(Controll Component)라고 부른다.
'개발' 카테고리의 다른 글
[ReactJS] 튜토리얼(Tutorial) - 8 (0) | 2017.06.10 |
---|---|
[ReactJS] 튜토리얼(Tutorial) - 7 (0) | 2017.06.10 |
[ReactJS] 튜토리얼(Tutorial) - 5 (0) | 2017.06.10 |
[ReactJS] 튜토리얼(Tutorial) - 4 (0) | 2017.06.10 |
[ReactJS] 튜토리얼(Tutorial) - 3 (0) | 2017.06.10 |
댓글