이번엔 객체와 배열에서 state를 활용해보자.

 

어떠한 버튼을 클릭했을때, sethistory의 state값이 변경되면서 

push 메소드를 활용하여 history값 뒤에 nextNum값 들을 추가해주는 코드이다.

이때 기존에 state 활용방식처럼 setHistory(history); 로 값을 넣어주었는데, 

이 방법은 사실 잘못된 방법이다. 

왜 일까? 

import { useState } from "react";
import Dice from "./Dice";
import React from "react";
import Button from "./Button";

const random = (n) => {
  return Math.ceil(Math.random() * n);
};

const App = () => {
  const [num, setNum] = useState(1);
  const [sum, setSum] = useState(0);
  const [history, setHistory] = useState([]);

  const handleRollClick = () => {
    const nextNum = random(6);
    setNum(nextNum);
    setSum(nextNum + sum);
    history.push(nextNum);
    setHistory(history);
  };

  const clearClick = () => {
    setNum(1);
    setSum(0);
    setHistory([]);
  };

  return (
    <div>
      <div>
        <Button onClick={handleRollClick}>던지기</Button>
        <Button onClick={clearClick}>처음부터</Button>
      </div>
      <h1>나</h1>
      <Dice color="red" num={num} />
      <h2>총점</h2>
      <p>{sum}</p>
      <h2>기록</h2>
      <p>{history.join(", ")}</p>
    </div>
  );
};

export default App;

코드에서

// setNum(nextNum);
// setSum(nextNum + sum);
 
이 부분을 주석처리 한 뒤, 코드를 실행해보면?
 
아무리 클릭해도 화면에 변화가 일어나지 않는다.

다른 state를 변경하는 부분만 바꿨으니까 기록부분은 바뀌어야하는데 바뀌지 않는다. 

이유는? history state가 배열이기 때문이다.

(배열은 기본형이 아니라 참조형)

그래서 history state는 배열의 기본 값을 그 자체를 가지고 있는게 아닌

배열을 가르키고 있는 주소 값을 가지고 있는 것이다.

push.메소드를 이용해서 배열에 새로운 값을 집어 넣어도 history 변수가 가지고 있는

배열의 주소 값은 변하지 않는다.

 

즉, 배열의 요소는 변하긴했지만 변수들이 가지고 있는

주소 값은 처음 그대로이기때문에 화면이 바뀌지않음.

리액트에서는 state값이 바뀌어야 새롭게 화면을 랜더하는데

아무리 새로운 요소가 추가된 배열을 setter함수에 넣었다고해도?

요소가 추가된 주소 값과 처음 주소 값은 같기때문에 state가 변경되었다고 판단하지 않는 것이다.

 

그래서 배열이나 객체같은 참조형 state를 변경할땐,

아에 전체를 새롭게 만든다고 생각하는게 더 편리하다.

가장 간단한 방법은

'스프레드 문법'을 활용!!!

[...history, nextNum]

복사했습니다!