useState와 불변성

이대영·2024년 9월 12일

state 만들기

State를 만들 때는 useState()를 사용한다.


onClick과 함께 사용한 useState

import React, { useState } from "react";

const App = () => {
  const [name, setName] = useState("초기값"); // 초기값 지정필요
  
  const handleNameChange = () => {
    setName("변경 완료"); // 변경되는 이름 지정
  }; // 이름을 변경하는 함수를 변수로 저장하여 정리

  return (
    <div>
      <h1>React State</h1>
      <button onClick={handleNameChange}> // 만든 변수를 이곳 { } 안에 작성
        이름을 변경하는 함수가 저장된 변수
      </button>
      {name}
    </div>
  );
};

export default App;

onChange와 함께 사용한 useState

import React, { useState } from "react";

const App = () => {
  const [text, setText] = useState(""); // 초기값은 빈 문자열

  const handleInputChange = (event) => {
    setText(event.target.value);
  };

  console.log(text);

  return (
    <div>
      <input type="text" onChange={handleInputChange} value={text} />
      {/* input태그는 항상 onChange와 value를 둘 다 연결 */}

      <div>{text}</div>
      {/* 변수화한 값을 지정한 text값을 다른곳에서 사용 가능! */}
    </div>
  );
};

export default App;

input에서 입력한 값을 변수에 저장하고 싶을 때 사용

React에서는 input 요소의 value 속성과 onChange 이벤트를 함께 사용하여 입력 필드의 상태를 관리하는 것이 일반적이며, 이러한 패턴을 제어 컴포넌트(Controlled Component)라고 한다.


불변성

메모리에 있는 값을 변경할 수 없는 것

변경 가능한 방법

let numbers = [1, 2, 3];
numbers.push(4); // 배열에 직접 요소를 추가
console.log(numbers); // [1, 2, 3, 4]
  • 위와 같은 방식이 문제가 되는 이유는 numbers.push(4)를 사용하는 방식이 문제가 되어 배열 numbers의 불변성을 깨뜨리기 때문이다.

  • 불변성을 깨뜨린다는 것은 원래의 데이터 구조를 직접 변경한다는 의미이므로, 이 경우에는 원본 배열 numbers에 직접적으로 새로운 요소 '4'를 추가하고 있음.


불변성이 깨지면 생기는 문제

  • 예측 불가능한 코드 데이터 구조를 직접 변경하면, 프로그램의 다른 부분에서 해당 데이터 구조를 참조하고 있을 때, 그 부분들도 예상치 못한 방식으로 변경될 수 있다. 따라서 알 수 없는 버그를 발생시킬 수 있고, 프로그램의 동작을 예측하기 어렵게 만듬.

  • 버그 추적의 어려움 : 원본 데이터가 여러 곳에서 변경될 수 있다면, 어떤 부분의 코드가 데이터를 변경했는지 추적하기 어려워진다.


불변성을 유지하는 방법

let numbers = [1, 2, 3];
let newNumbers = [...numbers, 4]; // 새 배열을 생성하여 기존 배열을 변경하지 않음
console.log(numbers); // [1, 2, 3]
console.log(newNumbers); // [1, 2, 3, 4]

리액트에서 불변성이 가지는 의의

리액트에서는 화면을 리렌더링 할지 말지 결정할 때 state의 변화를 확인한다.

  • state가 변했으면 리렌더링 O

  • state가 변하지 않았으면 리렌더링 X

state가 변했는지 변하지 않았는지 확인하는 방법은 state의 변화 전, 후의 메모리 주소를 비교하여 확인.


리액트 불변성 지키기 예시

  • 배열을 setState 할 때 불변성을 지켜주기 위해, 직접 수정을 가하지 않고 전개 연산자를 사용해서 기존의 값을 복사하고, 그 이후에 값을 수정하는 식으로 구현.

import React, { useState } from "react";

function App() {
  const [dogs, setDogs] = useState(["말티즈"]);

  function onClickHandler() {
		// spread operator(전개 연산자)를 이용해서 dogs를 복사. 
	  // 그리고 나서 항목을 추가.
    setDogs([...dogs, "치와와"]);
  }

  console.log(dogs);
  return (
    <div>
      <button onClick={onClickHandler}>버튼</button>
    </div>
  );
}

export default App;

추가 예시

import React, { useState } from "react";

function App() {
  const [items, setItems] = useState([1, 2, 3]);

  const addItem = () => {
    // * 틀린 코드
    // items.push(items.length + 1); // 배열에 직접 push = 불변성 위반, 작동안됨 => setItems 써라
    // setItems(items); //

    // * 옳은 코드
    setItems([...items, items.length + 1]); // 전개 연산자(...)를 사용하여 배열을 직접 추가 해주기
  };

  return (
    <div>
      <button onClick={addItem}>Add Item</button>
      <ul>
        {items.map((item, index) => (
          <li key={index}>{item}</li>
        ))}
      </ul>
    </div>
  );
}

export default App;

결론: state가 변했으니 리렌더링

0개의 댓글