Object(객체) 형태의 상태값을 다룰 때 주의할 점 - 프로퍼티 접근법, 얕은 비교
프로그래밍을 하다가 가장 힘든 순간 중 하나는 어떤 것에 대해 정확히 알고 있지 않은 나 자신을 발견했을 때 이다. 그게 쉬운 것인지 어려운 것인지는 그다지 중요하지 않다. 요즘은 주로 리액트로 코딩을 하는데 문득 내가 아직도 Object(객체)라는 녀석에 대해 정확히 모르고 있구나 라는 생각이 들었다. 그래서 기본적인 것부터 하나씩 다시 정리해보고자 한다.
1. 객체 프로퍼티 접근법
객체는 키(key)-값(value)의 형태로 구성된 프로퍼티들의 집합이다. 정확히 이야기 하면 키는 프로퍼티 키이고, 값은 프로퍼티 값인데 이 글에서는 키(key)와 값(value)으로 축약해서 부르겠다.
객체의 키는 우리가 ‘빈 문자열을 포함하는 모든 문자열 또는 symbol 값’(출처: poiemeweb의 객체) 으로 선언하면 암묵적으로 문자열 타입으로 변환한다. 즉, 자바스크립트 엔진이 선언된 객체의 키값을 보고 문자열로 변환할 수 있는 형태로 선언해야 한다.
person이라는 객체의 키를 선언할 때 name은 그냥 name
, phone-number는 "phone-number"
로 선언했다. 자바스크립트 엔진은 name을 바로 문자열로 변환할 수 있지만 그냥 phone-number
라고 썼을 때는 표현식으로 받아들이기 때문에 "phone-number"
라고 선언해줘야 한다. (참고: phone_number와 phoneNumber는 따옴표 없이 선언 가능)
객체의 키를 통해 값에 접근 하는 방법은 .와 []를 사용하는 방법이 있다. 만약 선언했을 때의 키값이 문자열이라면 name.person
, name['person']
으로 두 방법 모두 가능하다. 다만 선언했을 때의 키값이 표현식이라면 .으로 접근하는 것은 불가능 하고, name['phone-number']
만으로 접근해야 한다. 주의해야 할 점은 []로 접근하는 방식을 사용할 때 키값의 형태는 반드시 문자열이어야 한다.
codesandbox링크에서 객체 프로퍼티 접근법을 어떻게 활용하는지 확인해보자. 리액트에서 사용자 입력을 상태값으로 다루는 기본적인 코드이다.
2. 얕은 비교(Shallow Compare)
const [ state, setState ] = useState(initialState)
리액트에서 setState() 함수를 통해 상태값(state)을 바꿀 수 있다. 이전 상태와 다음 상태를 비교하는 과정을 거치고 같은 값이면 state를 변경하지 않고 다른 값이면 변경한다. 이 때, 성능상의 이득을 위해 얕은 비교(Shallow Compare)을 수행하기 때문에 만약 상태값이 객체 타입이라면 약간의 주의를 기울여야 한다. 얕은 비교을 이해하기 위해 참조 타입에 대해 짚고 넘어가보자.
자바스크립트 객체는 참조 타입 의 자료형인데, 변수에 할당될 때 데이터가 직접 할당되지 않고 데이터의 참조값(또는 주소값)이 할당 된다.
두 번째 줄인 let b = a;
코드를 통해 변수 a의 주소값이 변수 b에 할당 되었다. 이로써 a에 변경 사항이 생기면 b도 변하고, b에 변경 사항이 생기면 a도 변한다. 얕은 비교란 객체를 비교할 때, 주소값을 비교하는 것을 말하며 두 객체의 주소값이 같으면 ‘같다’, 다르면 ‘다르다’라고 판단하는 방법 이다. 따라서 변수 a와 b를 얕은 비교 했을 때 두 값은 같다. 이 말은 두 객체의 주소값만 다르게 주면 무조건 다른 객체로 판단 한다는 의미이기도 하기 때문에 리액트에서는 Object.assign()과 객체 구조분해 할당의 방법을 활용할 수 있다.
이전 상태값에 접근하여 직접 변경하는 것이 아니라 1) 이전 상태값을 복사하여 다른 주소값을 가진 객체를 만들고, 2) 수정하고 싶은 프로퍼티를 수정한 뒤 3)setState()
함수에 넘겨주면 의도한 비교 과정을 시도할 것이다. 마찬가지로 codesandbox링크로 확인해보자