프로필 편집 기능을 구현하다가 컴포넌트 내에 선언된 useState
와 일반 const
변수의 행동 차이를 유의미하게 관찰할 수 있게 되었다😶
useState
로 선언된 상태 변수 user
와 이를 참조하는 const
로 선언된 변수 preUserIntroduction
간의 상호작용에서 예상치 못한 결과를 마주했다.
나는 이것이 깊은 복사(deep copy)/얕은 복사(shallow copy) 개념과 관련이 있는 것인줄 알았다. 마치 state
변수는 깊은 복사를 하는 것이고, const
변수는 얕은 복사를 하는 것인가 싶었다.
그러나 나의 리액트 컴포넌트 라이프사이클에 대한 이해 부족이었다.
결론적으로는 둘 다 얕은 복사를 하는 것이고, const
변수는 컴포넌트가 마운트 될 때마다 참조되는 값이 새로 갱신되는 것일 뿐이었다.
export const EditIntroduction = ({ navigation }) => {
const [user, setUser] = useRecoilState(userState);
const preUserIntroduction = user.introduction;
const onPressConfirm = () => {
navigation.navigate('EditProfile');
};
const onPressCancel = () => {
setUser({ ...user, introduction: preUserIntroduction });
navigation.navigate('EditProfile');
};
// 생략된 UI 렌더링 부분
};
위의 코드에서 나는 preUserIntroduction
이 user.introduction
의 초기값을 그대로 유지하기를 바랐다.
그런데 사용자가 TextInput
의 onChange를 통해 user.introduction
을 변경하면 const preUserIntroduction
도 업데이트되는 현상이 있었다. 그래서 취소 버튼을 통해 onPressCancel
함수가 호출되더라도 초기의 user 값이 아닌 onChange로 인해 변경된 user 값이 user 상태 변수에 반영되었다.
export const EditIntroduction = ({ navigation }) => {
const [user, setUser] = useRecoilState(userState);
const [preUserIntroduction, setPreUserIntroduction] = useState[user.introduction];
const onPressConfirm = () => {
navigation.navigate('EditProfile');
};
const onPressCancel = () => {
setUser({ ...user, introduction: preUserIntroduction });
navigation.navigate('EditProfile');
};
// 생략된 UI 렌더링 부분
};
반면 preUserIntroduction
을 useState
로 관리했을 때는 TextInput
의 onChange를 통해 user.introduction
을 변경하더라도 preUserIntroduction
이 초기값을 잘 유지했다. 그래서 onPressCancel
함수가 호출되면 user 상태 변수에 초기의 user 값이 잘 반영되었다.
리액트의 렌더링 메커니즘에 따라const
변수는 컴포넌트의 렌더링마다 새로운 값으로 초기화된다. 컴포넌트의 상태가 변경되어 재렌더링이 발생하면, const
변수는 새로운 상태 값으로 갱신된다.
반면, useState
로 선언된 상태는 컴포넌트가 재렌더링 되어도 이전 상태를 유지하며, 오직 설정된 업데이트 함수를 통해서만 변경될 수 있다. 그래서 마치 깊은 복사를 하는 것처럼 보였던 것이다.
const와 state 변수의 차이를 이번에 제대로 알게 되었다!