저번 시간까지 게임판의 기본 요소 작업을 완료했습니다
오늘 작업할 내용은 게임을 할 때
두 플레이어가 순서대로 진행하도록
즉 돌아가면서 플레이하도록 하는 것이고
또 해당 플레이어의 기호가
버튼을 눌렀을 때
그 버튼에 표시되도록 하는 것입니다
추가로 더할 기능은
현재 차례인 플레이어를 표시하는 것입니다
예를 들면 이런 식으로
플레이어 이름에 테두리를 만드는 것입니다
사실 이것을 위한 CSS 형식을 미리 만들어 두었습니다
여기에 highlight-player라는 CSS 클래스가 있습니다
이것을 이 ol에 더하겠습니다
여기에 players 라는 id가 있기 때문입니다
이 클래스를 추가한다면
현재 차례인 플레이어 이름이 강조됩니다
이 강조 기능은 또한
다른 CSS 클래스인 active의 도움으로 실행됩니다
이것을 현재 차례인 플레이어의
list 항목에 추가하면 됩니다
여기에는 중요한 결과가 하나 따릅니다
즉 이것을 실행하기 위해서는
현재 차례인 플레이어에 대한 정보가 필요한데
필요한 정보는 이 Player 컴포넌트와
GameBoard 컴포넌트에 있습니다
그 플레이어의 기호 또한 알아야 하기 때문입니다
이 플레이어 컴포넌트에
CSS 클래스를 list 항목에 동적으로 추가하겠습니다
여기에는 문제가 하나 있습니다
이 둘은 각각 다른 컴포넌트인데
여기에서 필요한 작업은
각각이 모두 동일한 정보, 즉
어떤 플레이어가 진행 중인지를 알게끔 해야 합니다
이런 경우 주로 사용하는 방식이 있습니다
여기에서 할 작업은 바로
바로 상태(state) 끌어올리기 입니다
어떤 플레이어가 게임판에서 진행 중인지에 대한
그 정보를 각각 제어하는 것, 즉 게임판 컴포넌트와
플레이어 컴포넌트를 각각 보는 것은
이미 언급했듯 적절한 방식이 아닙니다
이 상태를 제어할 때
가장 가까운 부모 컴포넌트에서 하는 이유는
이 컴포넌트가 해당 정보를 필요로 하는
두 컴포넌트 모두에 대해 접근이 가능하기 때문입니다
이 경우 해당하는 컴포넌트는 App 컴포넌트입니다
App 컴포넌트에서는 어떤 플레이어가 진행 중인지
해당 정보를 두 컴포넌트 모두에게
속성(prop)을 통해 보낼 수 있기 때문입니다
그러므로 여기에 useState를 써서 상태를
앱 컴포넌트에 추가하여 현재 진행 중인 플레이어를 여기에서 제어하겠습니다
이 때 첫 번째 단계로
X 기호에 할당된 플레이어를
첫 번째로 진행하는 플레이어로 지정하고
setActivePlayer 상태 변경 함수를 추가해서
해당 플레이어 상태를 변경하도록 하겠습니다
이제 여기에 함수를 더해서
차례가 바뀔 때마다 실행되도록 하겠습니다
이름은 handleSelectSquare로 하겠습니다
왜냐하면 이 함수는 격자 게임판의 버튼을
클릭한 후에 순서를 바꾸도록 작동하기 때문입니다
이 함수에서는
현재 진행 중인 플레이어 상태를
setActivePlayer를 통해 호출하겠습니다
이 상태가 현재 X인지 확인한 후에
O로 변경하도록 하겠습니다
만약 O로 확인되면 X로 변경할 것입니다
즉, 새 상태는 이전의 상태에 기반하고
이것 때문에 이전과 같이
이 함수를 setActivePlayer로 넘기고
현재 진행 중인 플레이어를
자동으로 입력받게 됩니다
이것을 삼항 수식으로 확인하여
현재 진행 중인 플레이어에게 할당된
기호가 X인지 확인하겠습니다
이 경우라면 새로운 상태인 O로 변경하게 됩니다
반대의 경우, 현재 O라면 X로 변경하게 됩니다
이제 해야 하는 작업은
handleSelectSquare가
버튼이 하나 선택될 때 실행되도록 하겠습니다
물론 이 버튼은 모두
게임판 컴포넌트에서 제어됩니다
그러므로 속성을 받아서
속성 구조 분해 할당을 사용하여
받는 이 속성 이름을 onSelectSquare로 하겠습니다
이름은 임의로 지으셔도 됩니다
언제나처럼 이름을 지으실 때는
편한 이름으로 설정하시면 됩니다
그리고 이 함수를 호출하겠습니다
handleSelectSquare 내부에서 호출할 것인데
왜냐하면 이 함수가
버튼을 클릭하는 시점에 작동하기 때문입니다
onSelectSquare를 호출하는 이유는
이후에 어떤 함수를 실행하기 위해 필요합니다
이 함수는 게임판 컴포넌트 외부에서 정의되지만
이 함수를 이 컴포넌트 내부에서 사용하기 위해서입니다
이 onSelectSquare 속성값은
이미 아시듯이 함수여야 하고
이 함수를 여기에서 실행하기 때문입니다
이 실행된 함수가 정의되는 위치는
앱 컴포넌트 내부입니다
그 이유는
이 handleSelectSquare 함수가 바로
얼마 전에 추가한 함수이므로
이것에 대한 값이
새로운 onSelectSquare 속성에 대해 설정된 것인데
이렇게 할 수 있습니다
이제 이 코드는
버튼을 클릭했을 때 실행됩니다
지금 작업한 내용이
이 handleSelectSquare 함수를
게임판 컴포넌트 내부에서 실행하기 위함이었기 때문입니다
즉, 현재 진행 중인 플레이어를 변경하는 것이고
이제 두 가지 중요한 작업을 할 수 있습니다
먼저는 클래스 이름을 이 ol에 추가하고
이 highlight-player를 더하겠습니다
이 CSS 클래스를 바로 여기
이 ol에 넣겠습니다
그리고 다음으로는 정보를 전달하겠습니다
즉, 현재 진행 중인 플레이어가 누구인지에 대한 정보를
이 플레이어 컴포넌트에 전달하는 것입니다
그래서 여기에서 이 정보를
isActive로 이름 지은 속성을 통해 받게 됩니다
여기에 추가하고 구조 분해 할당하여
플레이어 컴포넌트에 포함시키겠습니다
그리고 이것을 이제 active(활성화)라는 속성으로 사용하여
클래스 이름을 동적으로 이 list 항목에 더할 수 있습니다
이것을 ifActive가 true인지 확인함으로써 해 보겠습니다
만약 true라면
active라는 클래스로 추가하고, 다른 경우에는 undefined (정의되지 않음)으로 추가됩니다
true가 아니라면 클래스를 추가하지 않아야 하기 때문입니다
이제 이 active라는 클래스를 조건부로
이 list 항목에 추가하겠습니다
이제 앱 컴포넌트에서
해야 할 일은
새로 받은 isActive 속성을
플레이어 컴포넌트에 더하는 것입니다
그리고 플레이어 컴포넌트를 처음 사용하는 여기에서는
이 플레이어는 활성화 되어 있는데 (isActive)
조건은 활성화된 플레이어(activePlayer)가
즉 여기에서 제어하는 상태가
X일 때입니다
이 이유는 이것은
X로 지정된 플레이어에 대한 함수이기 때문입니다
플레이어 컴포넌트를 사용하는 두 번째 부분에서는
기호 O를 찾아야 합니다
이 activePlayer 상태를 사용하겠습니다
이것은 여기에서 받아와서
여기에서 업데이트하여
어떤 플레이어의 차례인지 동적으로 강조 표시를 해 줍니다
그리고 이 activePlayer를 게임판(GameBoard)로 전달해야 합니다
activePlayer는 결국 현재 진행 중인
플레이어의 기호에 대한 것이고
이 기호가 현재 게임판에서
필요한 내용인데
이것을 클릭한 버튼에 두어야 하기 때문입니다
그래서 이 게임판 컴포넌트에서
activePlayerSymbol 속성을 받아오겠습니다
이름은 임의로 정하시면 됩니다
그리고 이 속성을 여기에 사용하겠습니다
지금은 일단 X만을 사용해서
게임판을 업데이트하고 있습니다
방금 클릭한 그 버튼을 업데이트하는 것입니다
이 activePlayerSymbol 속성은
게임판 컴포넌트에 설정해야 하는데
이 위치에 추가하겠습니다
그리고 이것을 activePlayer 상태로 설정해야 하는데
그 이유는
이것이 플레이어의 기호이기 때문입니다
그래서 activePlayer를
activePlayerSymbol에 값으로서 전달하겠습니다
일단 작업은 여기까지 하고
저장 후 확인해 보면
현재 진행 중인 플레이어에 강조 표시가 되어 있습니다
테두리에 멋진 모션이 들어가 있습니다
그리고 여기를 클릭하면 X가 나옵니다
그리고 이제 강조 표시가 넘어갔으므로
여기를 누르면 O가 나오게 됩니다
이렇게 서로 차례대로 진행할 수 있습니다
물론 아직 작업이 더 필요합니다
아직 이겼을 때의 기능이 없고
한 버튼을 여러 번 클릭할 수 있기 때문입니다
아직 미완성 상태이지만 많은 진전이 있었습니다
그리고 가장 중요하게는 이 개념을 배웠습니다
바로 상태 끌어올리기 (lifting state) 입니다
리액트에서 이 개념은 아주 중요합니다
리액트 앱을 빌드하는 과정에서
자주 필요한 내용이기 때문입니다