Vue 로 작업을 하던 중이었다. (2.x 버전)
data: {}
에 초기 데이터를 적어두고, 해당 데이터를 created()
라이프사이클에서 API 응답 결과의 데이터로 받아 데이터에 바인딩 하여 사용하고 싶었다.
data: {
target: {
foo: {
bar: ""
}
}
}
created() {
axios.post(...).then((res) => {
this.target = res.data; // 문제가 없어보이지만 문제가 발생한다.
})
}
위와 같이 사용하려고 하는데, HTML에서 데이터를 아무리 변경해도 반영이 되지 않았다.
심지어 크롬 브라우저 Vue 디버거를 이용해서 보면 데이터가 들어가긴 하는데 렌더링이 되지 않았다.
console.log로 여기저기를 들쑤시며 데이터가 제대로 바뀌는지, 어디서 놓친건지 한참을 찾으며 삽질했다.
해답은 Vue가 관리하고 있는 객체인지 아닌지를 보면 알 수 있었다.
data: {
target: {
foo: {
bar: ""
}
}
}
created() {
axios.post(...).then((res) => {
// 여기에서 target 이 새로운 객체를 참조하게 됨으로써 기존의 관리하던 객체를 잃어버린다.
this.target = res.data;
})
}
Vue의 data에 관리되는 객체인 target을 새로운 객체로 할당 해버리면서, target 이 기존에 참조하여 관리하던 객체를 잃어버려 더 이상 변경이 감지되지 않는 것이었다.
이는 Vue 공식 문서에도 나와있었다.
이를 해결하기 위해서는 Object.assign()을 이용하면 된다. 기존 객체의 참조값에 새로운 데이터를 넣어주기 때문에 계속해서 변경이 감지되도록 할 수 있다.
data: {
target: {
foo: {
bar: ""
}
}
}
created() {
axios.post(...).then((res) => {
// this.target에 res.data 객체의 property들을 추가한다.
Object.assgin(this.target, res.data);
})
}
이런 현상은 root 객체, 즉 1 depth 객체에만 해당이 된다.
만약 target 안에 있는 foo 의 값에 객체를 새로 할당하면, Vue는 여전히 target을 추적하고 있기 때문에 데이터가 변경되는 것을 감지할 수 있다.
data: {
target: {
foo: {
bar: ""
}
}
}
created() {
axios.post(...).then((res) => {
// target.foo 는 root객체가 아닌 target에 의해 참조되는 값으로, 계속 추적이 된다.
this.target.foo = res.data;
})
}
Vue를 많이 써보지 않아 부딪히게 된 어려운 문제였다.
이런 문제는 디버깅하기도 어려워서 찾아내기가 정말 힘든 것 같다.