리액트 - 참조형 state
배열, 객체같은 참조형 state를 다룰때 주의해야 한다.
▼ 주사위를 던지면 누적값을 알려주는 sum 표시하기
1. 이벤트 핸들러 수정하기 : handleRollClick(), handleClearClick()
2. 화면에 표시하는 부분에도 구현하기
function App(){
const [num, setNum] = useState(1);
const [sum, setSum] = useState(0);
const handleRollClick = () => {
const nextNum = random(6);
setNum(nextNum);
setSum(sum + nextNum);
}
const handleClearClick = () => {
setNum(1);
setSum(0);
}
return (
<div>
<div>
<Button onClick={handleRollClick}>던지기</Button>
<Button onClick={handleClearClick}>처음부터</Button>
</div>
<div>
<h2>나</h2>
<Dice color="blue" num={num}/>
<h2>총점</h2>
<p>{sum}</p>
</div>
</div>
);
}
이때 {setSum}이 아니라 {sum} 으로 적어줘야한다.
주사위 던진 값을 배열에 기록해서 화면에 보여주기
function App(){
const [num, setNum] = useState(1);
const [sum, setSum] = useState(0);
const [gameHistory, setGameHistory] = useState([]);
const handleRollClick = () => {
const nextNum = random(6);
setNum(nextNum);
setSum(sum + nextNum);
gameHistory.push(nextNum);
setGameHistory(gameHistory);
}
const handleClearClick = () => {
setNum(1);
setSum(0);
setGameHistory([]);
}
return (
<div>
<div>
<Button onClick={handleRollClick}>던지기</Button>
<Button onClick={handleClearClick}>처음부터</Button>
</div>
<div>
<h2>나</h2>
<Dice color="blue" num={num}/>
<h2>총점</h2>
<p>{sum}</p>
<h2>기록</h2>
<p>{gameHistory.join(', ')}</p>
</div>
</div>
);
}
그런데 사실 위 코드는 잘못된 코드다.
왜냐면
리액트는 state가 변했다고 인식했을때 변수가 가리키는 주소가 바뀌었을때를 말하고, 그때 화면을 새로 렌더링한다.
그런데 배열의 경우 새로운 숫자를 추가하더라도 배열의 주소는 바뀌지 않는다.
그래서 handleRollClick에서 setNum, setSum을 주석처리하면 setGameHistory에 의해서는 렌더링이 되지 않는다.
코드잇의 똑똑이 선생님께서 설명 글을 남겨주셨다...최고
일반형 데이터 = 숫자, 문자열, 불린 등의 자료형
참조형 데이터 = 배열, 객체, 클래스 등 복잡한 구조를 갖는 자료형
ex. A = {이름: '홍길동', 직업: '의사'} 라는 객체를 변수 A에 할당했다.
B = A ;
B.이름 = '박찬호' 라고 프로퍼티를 변경하면
console.log(A); 의 결과값으로 {이름: '박찬호', 직업: '의사'} 가 출력된다.
의도치않게 기존의 데이터를 덮게 됨
→ 배열/객체와 같은 참조형 데이터를 복사해서 써야한다. slice나 ... spread구문 사용 ▼
(메소드나 할당 연산자 사용 x )
setGameHistory()안에 배열 [] 써주는거 잊지 말기!
function App(){
const [num, setNum] = useState(1);
const [sum, setSum] = useState(0);
const [gameHistory, setGameHistory] = useState([]);
const handleRollClick = () => {
const nextNum = random(6);
setNum(nextNum);
setSum(sum + nextNum);
setGameHistory([...gameHistory, nextNum]);
}
const handleClearClick = () => {
setNum(1);
setSum(0);
setGameHistory([]);
}
return (
<div>
<div>
<Button onClick={handleRollClick}>던지기</Button>
<Button onClick={handleClearClick}>처음부터</Button>
</div>
<div>
<h2>나</h2>
<Dice color="blue" num={num}/>
<h2>총점</h2>
<p>{sum}</p>
<h2>기록</h2>
<p>{gameHistory.join(', ')}</p>
</div>
</div>
);
}