[React교양] state값을 변경할 때 이전이랑 같으면 렌더링하지 않는다.

state는 원래값과 변경값이 같으면  변경 액션 자체를 하지 않는다.

좀 더 정확하게 말하자면 `값` 을 비교한다기 보다 이전 값과 `메모리 주소` 가 변경되었는지를 판별한다.

 

💡 원시 데이터 타입 변경 예시

그럼 원시 데이터 타입에 대한 state 변경 예시를 알아보도록 합시다. 

 

state 정의

const [name, setName] = useState("길동")

state 변경

let copyName = name; // 길동 저장
copyName = '이황' // coppyName 변경
setName(copyName)

`name`을 `copyName`에 복사하고 값을 변경했다.  그리고 `copyName` 으로 변경 코드를 작성할 경우 우리는 당연히 변경된 값을 확인할 수가 있을 것이다. 

 

하지만 동일한 문자열값을 `setName()`에 전달하게 되면 어떻게 될까?

const copyName = name; // 길동 저장
setName(copyName) // name과 동일한 값을 전달

이번에는 `name`을 `copyName`에 복사하고 값을 변경하지 않았다. 이런 경우 우리는 변경되지 않은 텍스트가 보일 것이다. 여기서 이렇게 생각할 수 있다.  'setState()의 액션은 수행되었지만 텍스트가 같아서 변경되지 않은것 처럼 보인다.' 라고 생각할 수 있다.

 

하지만 실제로 액션도 수행되지 않은 것이 맞다. state는 값을 변경하기 전에 비교를 한 번 한다. (`원래값 == 변경값`) 그리고 값이 똑같을 경우 액션 자체를 수행하지 않게 된다. 여기서 근데 뭐 어쩌라고? 같은 생각이 들 수 있는데 자바스크립트에서 데이터는 크게 두 가지, `원시타입`과 `참조타입`이 존재한다.

 

간단히 말해 `원시타입`은 일반적인 숫자(123), 문자열("이름"), 논리형(true) 등의 1차원 적인 데이터를 의미하고 참조 타입은 객체, 배열, 함수 등이 있다. 참조 타입은 데이터를 복사할 때 값자체를 복사하지 않고 원본이 참조하고 있는 주소를 복사하게 된다. 여기서 객체의 깊은 복사얕은 복사라는 개념이 등장한다. 깊은 복사에 대해 정리한 글 (설명 잘 못하니까 다른 사람들이 정리한거 보는거 추천)

 

 

💡 참조 데이터 타입 변경 예시

그럼 이번에는 참조 데이터 타입의 state 변경 예시를 봅시다.

 

state정의 (배열)

let [name, setName] = useState(['길동', '이황', '이이'])

/* 대충 어떤 이벤트가 발생했을때 'name' 변경하는 함수 */
let copyName = name;
copyName[0] = '이름개명';
setName(copyName)
  • `name`에 이름을 담은 배열을 저장한다.
  • 이벤트가 발생했을때 `name[0]` 의 이름을 변경하려고 한다. 
  • 원본 변수(name)를 유지하고 싶어서 copyName이라는 변수를 생성해서 복사한다. 
  • `copyName[0]`의 이름을 변경하고 `setName()` 에 전달한다. 

위와 같이 코드를 작성할 경우 html에서 '길동' 이라는 텍스트가 '이름개명' 으로 리렌더링 되지 않는다.  위에서 설명했듯 state의 값을 변경할 때 원래값과 변경값을 비교한다고 했었다. 따라서 얕은 복사를 사용했기 때문에 둘의 `메모리 주소`가 같은 상태이다. 다시 말해 state입장에서 `name`과 `copyName`은 똑같다고 인식을 하게 되고 변경 액션이 수행되지 않는다. (배열 자체의 값은 변경됨, 하지만 html에 다시 렌더링 되지는 않음)

 

따라서 아래와 같이 코드를 수정해야 우리가 원하는대로 동작한다. 

let [name, setName] = useState(['길동', '이황', '이이'])

/* 대충 어떤 이벤트가 발생했을때 'name' 변경하는 함수 */
let copyName = [...name];
copyName[0] = '이름개명';
setName(copyName)

...spread 문법을 사용해서 배열이나 객체의 값들을 평탄화 시켜준 뒤 복사하면 원본주소가 아닌 새로운주소를 저장하기 때문에 state도 다른 값이구나! 라고 생각하고 우리가 원하는대로 동작할 것이다. 

 

※ 주의: 1차원 객체에 한해서만 spread로 복사가 가능함. 중첩 객체를 복사하려면 깊은 복사에 대해 좀 더 자세히 알아보셔야 됨

 

📍 정리

  • state로 값을 변경할 때 기존값변경값이 같을 경우 변경 액션 자체를 수행하지 않는다. 
  • 원본 데이터를 유지하고자 복사본을 만들어 변경할 경우 원시 데이터 타입은 정상적으로 동작한다. 
  • 참조 데이터 타입을 복사하여 사용할 경우 깊은 복사를 해주어야 한다.
  • 굳이 복사해서 사용하는 이유는 불변성을 유지 어쩌구 저쩌구 

댓글

Designed by JB FACTORY