리액트 State

웅평·2023년 7월 28일
0

State

state는 리액트에서 화면을 그려내는 데 굉장히 중요한 역할을 한다
State는 상태가 바뀔 때마다 화면을 새롭게 그려내는 방식으로 동작한다

import { useState } from 'react';

// ...

  const [num, setNum] = useState(1);

// ...

보통 이렇게 Destructuring 문법으로 작성하는데 useState 함수가 초깃값을 아규먼트로 받고 그에 따른 실행 결과로 요소 2개를 가진 배열의 형태로 리턴을 하기 때문이다

  • 첫 번째 요소가 바로 state이고, 두 번째 요소가 이 state를 바꾸는 setter 함수이다
  • 첫 번째 변수는 원하는 state의 이름(num)을 지어주고, 두 번째 변수에는 state 이름 앞에 set을 붙인 다음 카멜 케이스로 이름을 지어주는 것(setNum)이 일반적이다
  • state는 변수에 새로운 값을 할당하는 방식으로 변경하는 것이 아니라 setter 함수가 호출할 때 전달하는 아규먼트 값으로 state 값을 변경해 준다
import { useState } from 'react';

function App() {
  const [num, setNum] = useState(1);

  const handleRollClick = () => {
    setNum(3); // num state를 3으로 변경!
  };

  const handleClearClick = () => {
    setNum(1); // num state를 1로 변경!
  };

참조형 State

자바스크립트의 자료형은 크게 기본형(Primitive type)과 참조형(Reference type)로 나눈다

  const [gameHistory, setGameHistory] = useState([]);

  const handleRollClick = () => {
    const nextNum = random(6);
    gameHistory.push(nextNum);
    setGameHistory(gameHistory); // state가 제대로 변경되지 않는다!
  };

위 코드에서 볼 수 있듯 배열 값을 가진 gameHistory에 push 메소드를 이용해서 배열의 값을 변경한 다음, 변경된 배열을 setter 함수로 state를 변경하려고 하면 코드가 제대로 동작하지 않는다.

그 이유는 gameHistory state는 배열 값 자체를 가지고 있는 게 아니라 그 배열의 주솟값을 참조하고 있는 것이기 때문에 push 메소드로 배열 안에 요소를 변경했다고 하더라도 결과적으로 참조하는 배열의 주솟값은 변경된 것이 아니게 된다.

결과적으로 리액트 입장에서는 gameHistory state가 참조하는 주솟값은 여전히 똑같기 때문에 상태(state)가 바뀌었다고 판단하지 않는 것이이다

그래서 참조형 state를 활용할 때는 반드시 새로운 참조형 값을 만들어 state를 변경해야 한다.

const [gameHistory, setGameHistory] = useState([]);

  const handleRollClick = () => {
    const nextNum = random(6);
    setGameHistory([...gameHistory, nextNum]); // state가 제대로 변경된다!
  };

Spread 문법(...) 을 활용하면 해결할 수 있다

리엑트가 랜더링 하는 방식
리엑트는 내부에서는 DOM트리를 본떠서 만든 virtual DOM이라는 자료구조를 사용한다
그래서 엘리먼트를 새로 랜더링할 떄 리엑트트 그 모습을 실제 DOM트리에 바로 반영하는것이 아니라 virtual DOM에 일단 적용한다

State 변경 전의 virtual DOM과 변경 후의 virtual DOM을 비교한다
바뀐 부분만 찾아낸 다음에 각각 해당하는 실제 DOM 노드를 변경한다

이런식으로 핸더링하면 좋은점

  • 개발자가 직접 DOM 노드를 신경 쓸 필요가 없어서 단순하고 깔끔한 코드 작성 가능
  • 변경 사항들을 리엑트가 적당히 모아서 처리할 수 있다

참고
코드잇

0개의 댓글