Back

recoil value 프로퍼티 추가 오류

recoil atom으로 관리되고 있는 상태값을 useRecoilValue로 가져와서 객체에 프로퍼티를 추가하려고 했다.

const data = useRecoilValue(atomState);

data['key'] = value;

이 전역적으로 관리되는 상태값에 변화를 주려고 한 것은 아니다. useRecoilValue로 가져온 값을 화면에서 사용하는데 추가적인 변화를 주려고 한 것이다. 애초에 전역적으로 변화를 주려고 했으면 useSetRecoilState이나 useRecoilState에서 가져온 함수를 사용했을 것이다.

정확한 상태값의 형태는 객체 내부에 배열이 있고, 그 배열들은 각각 하나의 객체들을 값으로 가지고 있었다. 이를 map() 내부에서 필요한 프로퍼티를 추가하는 것이었다.

Uncaught TypeError: Cannot add property ~, object is not extensible

이런 오류가 나왔고, 디버깅을 하게 되었다.

이상하게 첫 map() 내부에서는 오류가 나지 않았으나, 두 번 째 부터는 위와같은 오류가 나왔다. (이건 왜 그런지 아직도 모르겠다.)

크롬 브라우저 개발자 도구에서는 이상하게 내가 직접 프로퍼티를 추가하면 오류가 나지 않으나, 실제로 디버깅을 통해 확인해보면, 오류가 나온다.

여러 삽질을 하고 결국 이는 순수한 object가 아니고, recoil atom에서 꺼내는 순간에 프로퍼티를 추가할 수 없도록 한 것이 아닐까 추측을 하게되었다. 검색을 해보니 이는 읽기 전용 프록시 객체여서 추가를 할 수 없는 것이라고 한다.

정말 헷갈리게 만드는 것 같다. typeof로 검사해도 그냥 object로 나오는데, 순수한 object가 아니라는 것을 어떻게 알 수 있을까? 검색해도 나오지 않고 브라우저 개발자 도구에서는 심지어 프로퍼티를 추가할 수 있어서 더 헷갈렸다.

lodash로 객체 깊은복사를 해서 프로퍼티를 추가하니 정상적으로 작동한다.

기존에 http response에서 가져온 값을 그대로 사용하다가, 이를 전역적으로 상태관리 하도록 변경을 하면서 발생한 문제인데, 그래서 더 파악하기 힘들었다.

상태관리 라이브러리에서 가져온 상태값에 뭔가 추가하면 이런 일도 발생할 수 있으니, 당황하지 말고 순수한 형태로 복사하는 과정을 거쳐야겠다.