본문 바로가기

3주차

🙄 리액트에서 배열의 값을 업데이트 하는 방법 (feat. 리액트의 불변성)

 

안녕하세요! 웹파트 OB 박채연입니다! 😋

이번주차 공유과제는 리액트에서 배열의 값을 업데이트 하는 방법에 대해 다뤄보려고 합니다!

 

지난 자바스크립트 과제에서 우리는 배열을 조작하고 배열을 이용해서 값을 업데이트하는 과정을 많이 구현했는데요.

과제 뿐 아니라, 우리가 화면에 보여지는 값을 조작하기 위해선 정말 많이 쓰이는 개념이 배열인 것 같아요!

 

근데 제가 리액트로 개발하면서 자주 들었던 피드백 중 하나가, "배열의 값을 직접 조작하기보단 복사된 새 배열을 이용해서 값을 업데이트 하는 게 어떠냐"는 내용이었어요. 이런 피드백을 들으면서, 바로 array.push 하면 배열에 쉽게 값을 넣을 수 있는데, 왜 굳이 새 배열에 ...array 하고 ~ 그 다음에 추가하고 ~ setUpdate(array) 하는 건지 이해가 되지 않았고, 이 부분에 궁금증을 갖고 공부하다보니 리액트의 불변성에 대해 알 수 있었습니다.  그래서 제가 했던 고민들과 그러면서 함께 공부했던 내용들을 공유하면, 많은 분들이 리액트의 불변성과 관련된 개념을 흐름에 따라 쉽제 이해하지 않을까~ 라는 생각에! 이번주차 공유과제로 해당 주제를 선정하게 되었습니다.

 

그럼 바로 가볼까요 💨

 


 

 

아래 코드는 신청자 목록 중에 ✅ 체크표시 된 사람들만 배열에 담는 과정을 구현했던 코드입니다.

const [checkedSubmitter, setCheckedSubmitter] = useState<SubmitterInfo[]>([]);

useEffect(() => {
	if (submitterList) {
    	const newArray: SubmitterInfo[] = [];
        checkedStates.map((checkedState, checkedStateIndex) => {
        	if (checkedState) {
            	newArray.push(submitterList[checkedStateIndex])
            }
        });
        setCheckedSubmitter(newArray);
    }
}, [checkedStates, submitterList]);

 

코드에 대한 간단한 설명을 덧붙이자면, checkedSubmitter 배열인 상태를 하나 만들어두고 만약 checkedState가 true일 경우, newArray 배열에 해당 신청자의 정보를 담은 후 setCheckedSubmitter를 이용해 newArray의 내용을 checkedSubmitter에 반영하는 과정입니다.

 

여기에서 checkedSubmitter를 let으로 선언하고, 그 배열에 바로 push하면 코드길이가 확 줄어드는데, 왜 굳이 state를 만들고, 새 배열을 만들어서 set하는 과정을 거치는 걸까요? 바로 리액트에서 배열의 값을 변경할 때, 불변성을 지켜줘야 하기 때문입니다.

 

 

불변성이 뭔데?

값이나 상태를 변경할 수 없는 것을 말합니다. 메모리 영역에서 값이 변하지 않는 것을 의미하죠!

 

 

그럼 왜 리액트에서 불변성을 지켜줘야 하는건데?

리액트가 상태를 업데이트하는 원리 때문입니다. 리액트는 상태값을 업데이트 할 때, 얕은 비교를 수행합니다. 즉, 배열이나 객체의 속성 하나하나를 비교하는 것이 아니라, 이전 참조값과 현재 참조값만을 비교해 상태 변화를 감지한다는 것이죠.

 

 

얕은비교는 무엇이고, 왜 얕은 비교를 수행하는 건데?

리액트의 얕은 비교는 아래와 같이 일어납니다.

(1) 숫자나 문자열, boolean 같이 원시값을 가진 자료형은 값을 비교한다.
(2) 배열, 객체 등 참조값을 가진 자료형의 경우, 그 안의 값이나 attribute를 비교하지 않고, 그들의 레퍼런스 (참조되는 위치)를 비교한다.

 

얕은 비교는 계산 리소스를 줄여주기 때문에, 효율적으로 상태를 업데이트 할 수 있습니다.

그렇기 때문에 얕은 비교를 수행하는 것이죠.

 

 

불변성을 지키지 않으면?

불변성이 지켜지지 않을 경우 원본 데이터가 변경될 가능성이 생기고, 그렇게 된다면 원본 데이터를 참조하고 있는 다른 객체에서도 예상치 못한 오류가 발생할 수 있습니다. 또한, 어디에서 어떤 동작이 일어날 지 예상하기 어려워지므로 프로그래밍 구조가 단순하게 느껴지지 않을 수 있기도 하죠! 그러니까, 불변성을 지키기 위해 원본값을 직접 변경하지 않는 겁니다!

 

 

새로운 객체를 생성해 상태를 업데이트 하도록 권장하는 리액트

리액트는 상태가 변경될 때마다 컴포넌트를 리렌더링합니다. 상태가 변경되었는지 감지하기 위해 이전 상태와 새로운 상태를 비교하는데, 상태를 직접 변경하면 참조 값이 동일하게 유지되기 때문에 리액트가 상태 변경을 감지할 수 없게 됩니다. setState 함수를 사용해서 배열을 업데이트하면 새로운 객체가 생성되고, 그러면 리액트는 상태가 변경되었음을 정확하게 인식할 수 있습니다. 따라서 상태를 직접 밴경하지 않고, 새로운 객체를 생성해 상태를 업데이트 하는 것이 리액트가 권장하는 방식입니다.

 

 


 

저는 처음 이 부분에 대해 공부할 때, 배열의 값을 직접 변경하지 않고 새 배열을 만들어 배열의 값을 업데이트 하는 이유에 대해 궁금했던 것 뿐이었는데.. 리액트의 상태 업데이트 원리, 얕은 복사, 불변성 등 다양한 개념들을 인지해야 그 이유를 알 수 있더라구요. 그래서 느꼈던 점이 있다면, 리액트 뿐 아니라 모든 개념들은 끊임없이 엮여있다는 것, 그리고 리액트의 동작 원리에 대해 깊게 파다보면, 더 좋은 방식으로 코드를 짤 수 있겠다는 것.. 이 두가지 입니다! 😁 그래서 더더욱 궁금한 것들이 생기면 왜? 왜? 왜? 하면서 꼬리를 물고 공부하고, 그러다보면 리액트에 대한 깊은 이해를 할 수 있게 되어서, 리액트가 더 재미있어지는 기분.. (아닌가) 

 

하튼! 리액트에서 배열을 다룰 때 불변성, 상태 업데이트 원리와 같은 개념들을 인지하고 있으면 좋을 것 같습니다.

그냥 다들 배열 업데이트 할 때 이렇게 하니까~ 해왔던 분들도 이유를 확실히 알아두면 더 좋겠죠?!

그럼 안뇽.

'3주차' 카테고리의 다른 글

[React] 리렌더링에 대해 알아보자  (3) 2024.11.02
useEffect, 클린업 함수, useLayoutEffect, useRef  (0) 2024.11.02
컴포넌트와 Props  (0) 2024.11.02
리액트의 flux 패턴  (0) 2024.11.02
React에서의 '상태관리' 😎  (0) 2024.11.02