저번 시간까지는
이 gameBoard 값을 계산하되
이 gameTurns 상태에 기반하도록 했습니다
이 상태는 앱 컴포넌트에서 제어되고
속성을 통해 GameBoard 컴포넌트로 넘어갑니다
여기에 기능을 더하기 전에
이 앱 컴포넌트를 다시 보겠습니다
여기에 더 계산해야 하는 것이 있을까요?
지금 상태로 사용하고 있는 것은 어떨까요?
질문에서 이미 눈치채셨겠지만 그것을 봐야 합니다
바로 이 activePlayer 상태입니다
현재로서는 이것을 상태로서 제어하고 있습니다
이 코드를 잠깐 훑어본 사람에게는
그렇게 하는 것이 맞다고 느껴질 것입니다
그 이유는
플레이어가 매 차례마다 바뀌어야 하기 때문입니다
그 떄마다 이 UI를 업데이트해야 하는데
예를 들면 이름 주변의 강조 표시도 바뀌어야 하고
버튼 위에 쓰일 기호도 역시
달라져야 하기 때문입니다
그러므로 UI 업데이트가 필요하니
이것을 상태로서 제어하는 것은 타당할까요?
그렇지 않습니다
상태가 UI 업데이트를 실행하는 것은 맞지만
꼭 기억해야 하는 것은
이미 여기에 gameState 상태가 있다는 점입니다
이 상태는 버튼을 선택할 때마다 이미 변하고 있습니다
즉 버튼을 클릭할 때마다 실행됩니다
그러므로 이 activePlayer 상태를 추가로 더해서
UI 업데이트를 실행시킬 필요는 없습니다
물론 여기에서 필요한 정보는
현재 어떤 플레이어가 진행 중인지에 대한 정보입니다
그러나 이 정보는 gameTurns에서 가져올 수도 있습니다
그리고 이 함수에서 하고 있는 일 또한
정확히 그것입니다
setGamesTurns를 거쳐가기 때문입니다
여기에서는 activePlayer를 차례에 대한 상태 변화로 파생시킵니다
이것은 이전 차례에 기반한 내용입니다
물론 이 앱 컴포넌트에서도 동일한 작업을
할 수 있습니다
activePlayer 상태를 따로 만들지 않고도
이 부분을 삭제하고도 파생된 상태를 더할 수 있고
여기의 로직을 복사해올 수 있습니다
그러나 차이점이 있는데
앱 컴포넌트에서는
현재 진행 중인 플레이어 정보를
이전의 gameTurns 상태에 기반해서 받지 않습니다
대신 현재의 gameTurns 상태를 사용하도록 하겠습니다
prevTurns를 gameTurns로 대치하겠습니다
이제 현재 진행 중인 플레이어의 기호를
gameTurns에서 파생시키고 있습니다
코드는 거의 똑같아 보이지만 이렇게 함으로써
이 부분을 삭제할 수 없다는 것을 알 수 있습니다
이 함수 내부를 보면 알 수 있습니다
이 함수는 setGameTurns로 보내는 것인데
여기에서 상태를 이전의 gameTurns 상태로부터 파생시켜야 합니다
반대로 앱 컴포넌트에서는
현재 gameTurns 상태에서 파생시킵니다
그러므로 이미 언급했듯이
이전 상태에 기반하여 상태를 변경할 때에는
이런 식으로 해야 합니다
물론 여기서 할 수 있는 일은
헬퍼(helper) 함수를
컴포넌트 함수 바깥에 하나 만드는 것입니다
이 헬퍼 함수는 컴포넌트와 관련된 그 어떤 상태나
데이터에 접근할 필요가 없기 때문입니다
이것은 또한 컴포넌트 함수가 재실행될 때
스스로 재실행하지 않아도 됩니다
이름은 deriveActivePlayer로 하겠습니다
입력값으로는 gameTurns를
단순 표준 매개변수로 받겠습니다
그리고 이 코드를 복사해서
deriveActivePlayer에 붙여넣고
여기에서 currentPlayer를 반환하겠습니다
이제 헬퍼 함수가 정의되었으니
다시 컴포넌트 함수로 돌아와서
이 부분의 코드를
currentPlayer라는 상수로 대치하겠습니다
activePlayer나 다른 이름으로 하셔도 됩니다
이 상수는 deriveActivePlayer 호출의 결과를 저장하고 있습니다
즉, 방금 추가한 이 함수입니다
여기에서 gameTurns 상태를 인자로서
deriveActivePlayer로 전달하겠습니다
그러므로 여기에서 이용이 가능합니다
이렇게 각 부분이 서로 연관되어 실행됩니다
여기에는 activePlayer가 있습니다
이 상태 업데이트 함수에서는 또한
이 코드를 대치하고
deriveActivePlayer를 호출하여 currentPlayer를 설정할 수 있습니다
그러나 이제는 gameTurns를 인수로서
이 함수로 보내지 않고 대신 prevTurns를 사용합니다
이제 중복되는 코드를 정리했습니다
여전히 activePlayer가 있지만
추가 상태를 제어하지 않도록 조치했습니다
리액트 코드 작성 시에는 이런 식으로
작업하셔야 합니다
상태는 최대한 적게 사용하도록 하고
최대한 많은 값을 파생 및 연산하도록 하는 것입니다
이제 저장 후 새로고침을 해 보겠습니다
오류가 없는 것을 확인할 수 있고
버튼을 눌러서 게임을 플레이할 수 있습니다
이제 여기에서 남은 작업은
같은 버튼을 여러 번 누르지 못하도록 하는 것입니다
지금은 그것이 가능합니다
그리고 다음 단계는 게임이 끝났는지
진행상황을 확인하는 것입니다