일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- Class
- 깃
- Git
- Collection 인터페이스
- 깃허브
- GitHub
- 이클립스
- 자바
- Eclipse
- 버전관리
- java
- CSS
- 싱글톤 패턴
- 오류
- html
- Method
- 이클립스 설치
- 메서드
- Collection Framework
- 인터페이스
- singlrton pattern
- 클래스
- 해결
- 컬렉션 프레임워크
- Map 인터페이스
- 패키지
- Today
- Total
안루피취뽀일기
State(상태)를 끌어올리면 안되는 경우 본문
틱택토 게임 개발 중
아직은 위 캡쳐본처럼 게임 승자의 닉네임이 아닌 symbol(O랑 X)로 표기되고 있어서
이것을 승자의 닉네임을 가져오도록 하고 싶었다.
App 컴포넌트 내에 플레이어의 이름에 대한 정보가 필요한 것을 의미한다.
그리고 현재 플레이어의 이름 정보는 Player 컴포넌트 내에 저장되어 있다.
Player 컴포넌트 -> 플레이어의 이름을 편집하고 저장하는 곳.
<Player
initialName="Player 1"
symbol="X"
isActive={activePlayer === "X"}
/>
<Player
initialName="Player 2"
symbol="O"
isActive={activePlayer === "O"}
/>
애플리케이션 내의 그 어떤 부분하고도 이 이름을 공유하지 않는다..!
따라서 Player 컴포넌트로부터 플레이어의 이름들을 얻어서 App 컴포넌트로 가져와야 한다.
그렇다면...먼저드는 생각이
이 플레이어 이름 상태를 Player 컴포넌트에서 App 컴포넌트로 끌어올리면 되지 않을까??!
그렇다. 틀렸다.
Because
import { useState } from "react";
export default function Player({ initialName, symbol, isActive }) {
const [playerName, setPlayerName] = useState(initialName);
const [isEditing, setIsEditing] = useState(false);
function handleEditClick() {
setIsEditing((editing) => !editing);
}
function handleChange(event) {
setPlayerName(event.target.value);
}
let editablePlayerName = <span className="player-name">{playerName}</span>;
if (isEditing) {
editablePlayerName = (
<input
type="text"
required
defaultValue={playerName}
onChange={handleChange}
/>
);
}
return (
<li className={isActive ? "active" : undefined}>
<span className="player">
{editablePlayerName}
<span className="player-symbol">{symbol}</span>
</span>
<button onClick={handleEditClick}>{isEditing ? "Save" : "Edit"}</button>
</li>
);
}
위에는 전체 Player 컴포넌트의 코드인데
플레이어 이름 상태는
매 타이핑마다 이 입력 필드를 업데이트 하는 것에 사용되기 때문이다.
그리고 만약 이것을 Player 컴포넌트로부터 이동시키려 한다면
App 컴포넌트 전체가 매 타이핑마다 재평가된다는 것을 의미하게 된다..!
추가적으로, 이 플레이어 이름 상태를 Player 컴포넌트로부터 끌어올리는 것 또한 까다롭다.
왜냐하면 2인용 게임이니까 Player 컴포넌트를 두 번 사용하고
각 컴포넌트가 고유의 이름을 관리해야 하기 때문이다.
따라서 Player 컴포넌트는 지금 방식으로 그대로 유지되어야 한다.
대신 App 컴포넌트에 useState를 활용하여 단순히 새로운 상태를 추가한다.
const [players, setPlayers] = useState({
X: "Player 1",
O: "Player 2",
});
이곳은 최근 설정된 플레이어의 이름을 저장하는 곳이다.
그리고 이 State는 초기에 Player 1과 Player 2와 같이 두 개의 이름이 있는 배열이 될 수 있다.
하지만 이 플레이어의 이름들이 각각의 symbol에 연동되어 있기 때문에
map으로 객체를 사용해준다..!
즉, 여기서 키 X와 해당 키에 대한 값은 Player 1이고, 키 O는 Player 2이다.
그러면 useState에서 얻은 배열을 분해 구조 할당할 수 있다!
setPlayers는 Player 컴포넌트 내에서 저장 버튼을 누를 때마다 호출되어야 한다.
키를 누를 때마다가 아닌..! 플레이어 이름의 변경 사함을 저장할 때만이다!
따라서 당연히 App 컴포넌트 함수 내에서 새로운 함수를 추가해줘야겠죠
function handlePlayerNameChange(symbol, newName) {
setPlayers((prevPlayers) => {
return {
...prevPlayers,
[symbol]: newName,
};
});
}
여기서 이름이 변경된 플레이어의 symbol과 newName을 전달 인자로 받는다.
그러고 난 후 setPlayers를 호출한다.
이전 상태를 기반으로 상태를 업데이트해야 하는데 왜냐면
오직 한 플레이어의 이름만이 여기서 변경되기 때문이고
다른 플레이어의 이름과 정보를 잃으면 안되니까!
결론적으로 이곳에서는 prevPlayers를 얻고
새로운 상태가 될 그리고 새로운 플레이어의 상태일 새로운 객체를 반환한다.
...prevPlayers,
이전 플레이어의 객체를 펼쳐서 다시 X와 O의 속성을 각각 이전 플레이어의 이름으로 설정한다.
하지만 둘 중 하나의 속성을 다시 덮어쓸 것이다.
여기서 얻는 속성은 symbol 매개변수의 도움을 받는다.
[symbol]: newName,
symbol에 저장된 내용에 따라 새 이름으로 설정한다.
이 접근을 통해 플레이어의 변하지 않는 이름과 기호를 유지하도록 한다.
그리고 단지 변경된 플레이어의 기호에 대한 이름을 덮어쓰는 것이다.
그리고 이제
handlePlayerNameChange가 실행될 때마다
Player 컴포넌트 내에서 이루어지도록 해야한다.
이 변경사항은 Save 버튼을 누르면 확인된다.
따라서 onChangeName이라는 property를 이용해야 한다.
<Player
initialName="Player 1"
symbol="X"
isActive={activePlayer === "X"}
onChangeName={handlePlayerNameChange}
/>
<Player
initialName="Player 2"
symbol="O"
isActive={activePlayer === "O"}
onChangeName={handlePlayerNameChange}
/>
onChangeName={handlePlayerNameChange}
그리고 Edit 버튼이 클릭될 때마다 실행되는 handleEdit 함수에서
function handleEditClick() {
setIsEditing((editing) => !editing);
if (isEditing) {
onChangeName(symbol, playerName);
}
}
onChangeName을 호출하고 첫 번째 전달 인자로 symbol을 전달한다.
왜냐하면 handlePlayerNameChange에서 첫 번째 parameter 로 symbol를 기대하고
두 번째 매개변수 로 newName을 예상하기 때문이다.
Player 컴포넌트 내에서 onChangeName으로 전달하는 두 번째 인자는 playerName 이다.
여기에 if (isEditing) { }를 추가한다.
왜냐하면 만약 isEditing이 true라면 그 버튼을 눌러서 편집을 멈춘 것을 의미한다.
이제 이로써 여기 App 컴포넌트 내에 players 상태를 활용하여
게임이 끝났을 때 올바른 플레이어의 이름을 보여줄 수 있다.
winner = players[firstSquareSymbol];
\
허허
'React' 카테고리의 다른 글
styled-components 배운거 두서없이 정리 (0) | 2024.03.02 |
---|---|
양방향 바인딩 (0) | 2024.02.22 |
조건적 콘텐츠 & State(상태) 업데이트 !매우간단하지만 중요한! (0) | 2024.02.01 |
[S.WITH] 3일째 해결 못하고 있는 post_no undefined오류.. (0) | 2024.02.01 |
감싸진 요소에 Props(속성) 전달하기 (0) | 2024.01.29 |