[React] state 불변성

youngseo·2022년 5월 15일
0

REACT

목록 보기
10/52
post-thumbnail

state 불변성

프로그래밍에서 불변성을 지킨다는 것은 메모리 영역의 값을 직접적으로 변경하지 않는다는 것입니다.

만약 setState()의 ()안에 불변성을 지키지 않고, 메모리 영역의 값을 직접 변경하는 값을 넣어주면 리액트는 state가 바뀌었다고 인지를 하지 못합니다. 따라서 리렌더링이 일어나지 않습니다.
왜냐하면 리액트는 이전 state 과 이후 state 를 비교할 때, 얕은 비교 (Shallow Compare)를 하기 때문입니다.(얕은 비교는 메모리가 같다면 같다고 비교를 합니다.)

원시타입 과 참조타입

  • 원시타입의 경우 불변성을 가지고 있습니다. 만약 변수에 원시타입의 값을 저장하면 메모리에 값 자체가 저장되게 됩니다.
  • 반면 참조타입의 경우 불변성을 가지고 있지 않습니다. 만약 변수에 참조타입의 값을 할당하는 경우 메모리 값이 담긴 주소가 저장되게 됩니다.
  • 따라서, 참조타입은 불변성을 가지도록 호출을 해줘야합니다.

1. 원시타입 다루어보기

  • +버튼을 클릭하면 counter의 숫자가 증가
  • Show and Hide 버튼을 클릭하면 counter가 나타나거나 사라집니다.
  • Change Oprerator버튼을 클릭하면 +,-,* 중 랜덤하게 선택 및 계산을 해 counter에 적용되도록 로직을 짜보겠습니다.
import React, {useState} from 'react'

export default function Counter() {
  //값, 값을 변경할 때 쓰는 함수
  const [count, setCount] = useState(0);
  const [show, setShow] = useState(true)
  //+, -, *
  const operators = ["+","-","*"]
  const [ operator, setOperator ] = useState(operators[0])

  return (
    <div>
      <button onClick={() => {
        let result;
        if(operator === "+") result = count + 1
        if(operator === "-") result = count - 1
        if(operator === "*") result = count * 1
        setCount(result)
      }}>{operator}1</button>
      <button onClick={() => setShow(!show)}>Show and Hide</button>
      <button onClick={() => {  //랜덤하게 값을 꺼낼 수 있도록 값을 계산하는 로직을 작성
        const idx = Math.floor(Math.random() * operators.length)
        setOperator(operators[idx])
      }}>Change Operator</button>
      <br/>
      { show && `Counter : ${count}`}  //조건부 렌더링(show가 true인 경우에만 보이게)
       
    </div>
  )
}

2. 참조타입 다루어보기

useState를 세번 사용해 state변수를 3개 만들었었지만 이를 하나의 객체로 관리를 한다면 다음과 같을 것입니다.

  const [count, setCount] = useState(0)
  const [show, setShow] = useState(true)
  const [operator, setOperator] = useState(operators[0])

  =>
  
  const [info, setInfo] = useState({
    count: 0,
    show: true,
    operator: operators[0]
  })
import React, {useState} from 'react'

export default function Counter() {
  const operators = ["+","-","*"]

  //state를 하나의 객체로 관리
  const [info, setInfo] = useState({
    count: 0,
    show: true,
    operator: operators[0],
  })

  return (
    <div>
      <button onClick={() => {
        let result;
          //info.으로 접근 할 수 있도록 수정해줍니다.
        if(info.operator === "+") result = info.count + 1
        if(info.operator === "-") result = info.count - 1
        if(info.operator === "*") result = info.count * 1
        setInfo({...info, count : result})
        // setCount(result)
      }}>{info.operator}1</button>
      <button onClick={() => {// 리액트가 주소를 관리하고 있기 때문에 아래의 경우 상태값이 변경되었다고 인지를 하지 못합니다.
        // info.show = !info.show
        // const newInfo = info
        setInfo({...info, show : !info.show})
      }}>Show and Hide</button>
      <button onClick={() => { 
        const idx = Math.floor(Math.random() * operators.length)
        // setOperator(operators[idx])
        setInfo({...info, operator: operators[idx]})
      }}>Change Operator</button>
      <br/>
      { info.show && `Counter : ${info.count}`}
       
    </div>
  )
}

0개의 댓글