[React] useState의 불변성

김태훈·2022년 2월 3일
0

React

목록 보기
6/9

이번에는 react에서 가장 많이 쓰이는 Hook인 useState에 대해 알아보고자 합니다.

기본적인 사용법은

import React, { useState } from 'react';

const [state, setState] = useState('initialValue')

위와 같이 useState를 import 해주신 다음 useState를 선언해 주시면 됩니다.

state의 값은 setState를 통해 변경할 수 있는데요.

이 때 주의하셔야 하는 부분이 있습니다.

불변성 (useState)

바로 불변성인데요.

여기서 불변성이란, 메모리 영역에서의 직접적인 변경이 불가능하다는 뜻으로 기존 state의 불변성을 지켜주어야만 상태가 업데이트가 됐음을 감지해 리렌더링이 가능해집니다.

그럼, 불변성을 지키기 위해서 어떻게 해야 할까요?

state의 값을 직접 변경하는 것이 아닌 얕은 복사를 활용해 새로운 객체나 배열을 만들어 새로운 변수에 할당하는 식으로 사용해야 합니다.

const newPeople = people.filter((person) => {
  return person.id !== id;
});

setPeople(newPeople);

위처럼 말이죠.

예시 코드처럼 새로운 배열을 만들어 할당을 해줬을 때 리액트는 컴포넌트를 리렌더링할 수 있습니다.

그럼 조금 더 복잡한 예시로 가보도록 하겠습니다.

const [isOpen, setIsOpen] = useState(false);

const favorData = async (isFavorites) => {
const [data, error] = await getMyBookmarksApi(isFavorites);
  if (data) {
    const newList = data.markedList.map((el) => {
      return (
        <CourseCard
          key={el.courseInfo.id}
          regStatus={isFavorite}
          course={el}
          isOpen={isOpen}
          setIsOpen={setIsOpen}
        />
      );
    });
    setFavorList(newList);
  } else {
    console.dir(error);
  }
};

다음과 같은 코드가 있다고 가정해봅시다.

위의 코드에서는 isOpen의 값과 setIsOpen이 CourseCard의 props로 전달되어 CourseCard 컴포넌트 내에서 setIsOpen을 통해 값을 설정해 부모 컴포넌트로 전달해줍니다.

결국,

<CourseCard
	key={el.courseInfo.id}
	regStatus={isFavorite}
	course={el}
	isOpen={isOpen}
	setIsOpen={setIsOpen}
/>

안에서만 isOpen 값이 바뀌게 되는 것이죠. 이렇게 바뀐 값은 다시 newList로 할당되게 되는데 이때 이 컴포넌트는 isOpen값이 바뀌었으니 다시 랜더링이 될까요?

답은 "랜더링 되지 않는다" 입니다.

왜냐하면 배열의 얕은 복사를 통해 할당된 newList라는 배열은 data의 map함수의 return 값의 변화와는 상관이 없이 새로운 배열을 그대로 유지하기 때문입니다.

??? 아까는 얕은 복사를 사용하면 된다고 하지 않았나요 ???

얕은 복사도 객체의 depth 1 까지밖에 복사가 되지 못하기에 더 깊은 곳에 있는 값들은 복사가 되지 않는 특성이 있습니다.

이를 해결하기 위해서는 CourseCard의 컴포넌트 내에서 isOpen 의 useState를 새로 만들든가 useEffect를 통해 컴포넌트를 다시 랜더링 시켜야합니다.

useEffect를 통해 컴포넌트를 다시 랜더링 시켜주는 방법은 최적화의 측면에서 좋지 못한 방법이기에 새로운 컴포넌트로 빼서 작업하시는 방법을 추천드립니다.

profile
1일 1커밋 1블로그!

0개의 댓글