원문 : http://michaelnthiessen.com/how-to-watch-nested-data-vue/
앱은 배열이나 객체의 데이터 속성을 가질 수 있다. 그리고 당신은 데이터가 변경될 때마다 앱이 무엇가를 수행하길 원한다.
그래서 watch
속성을 만들 것이다, 하지만 Vue는 중첩된 데이터의 변경에 대해서는 watch
하지 못한다.
다음은 이를 해결하는 방법이다.
객체나 배열을 watch
할 때 deep
속성을 설정하여 Vue에게 중첩된 데이터를 watch
해야 한다고 알릴 필요가 있다.
이 글에서 중첩 데이터와 deep
속성이 어떻게 생겼는지, 그리고 watch
속성을 사용할 때 유용하게 써먹을 수 있는 것들을 더 자세히 설명하겠다.
또한 Vue 문서의 watch
사용법을 확인하면 도움이 될 것이다.
우선 watch
가 무엇인지 빠르게 복습해 볼 것이다.
둘째, 주제에서 약간 우회하여 computed
과 watch
의 차이점을 명확히 알아볼 것이다.
셋째, 배열과 객체에서 중첩된 데이터를 watch
할 수 있는 방법에 대해 살펴볼 것이다. 필요한 경우 부담없이 앞부분을 건너띄고 여기부터 읽어도 좋다(앞부분이 궁금하면 언제든지 앞부분으로 돌아와 확인하면 된다).
또한 우리는 watch
의 immediate
와 handler
속성으로 무엇을 할 수 있는지 살펴볼것이다. 이 과정은 당신의 watch
사용 스킬을 한 차원 높여 줄 것이다.
그러나 그 전에 꼭 알려주고 싶은 좋은 소식이 있다.
매일 많은 사람이 내가 쓴 글을 읽고 있다는 사실에 놀랐다. 진정 겸손하게, 내가 계속해서 글을 쓰는데 동기부여가 된다.
당신에게 감사드리고 싶었다.
나는 당신이 Vue 앱을 만들 때 겪게 될 가장 일반적인(좌절감을 주는) 문제를 해결하는 144페이지 분량의 책을 썼다.
이 책은 반응성 문제를 다루는 것 부터 혼란스러운 오류를 이해하는 것까지의 모든 것을 다룬다.
또한, 일반적인 동작들(클래스를 동적으로 변경하는 것과 같은)을 올바른 방법으로 구현하는 방법을 살펴볼 수 있을 것이다.
제일 좋은 부분은? 이 책을 돈을 받고 판매할 수 있음에도, 무료로 제공하고 있다는 것이다.
Vue에서 속성이 변경될 때 우리는 변화를 지켜보고, 변화에 대응하는 무언가를 할 수 있다.
예를 들면, colour 속성(prop)이 변할때 콘솔에 로그를 기록하게 할 수 있다.
export default {
name: 'ColourChange',
props: ['colour'],
watch: {
colour()
console.log('The colour has changed!');
}
}
}
watch
는 많은 경우에 유용하게 사용할 수 있다. 하지만 computed
속성만으로도 충분한 문제를 watch
를 사용해서 해결하는 경우가 많다.
watch
를 사용할 것인가 computed
를 사용할 것인가?watch
속성은 computed
속성과 비슷한 방식으로 작동하기 때문에 종종 혼동된다. 언제 어느 것을 사용할 지 아는 것은 더 까다롭다.
그러나 나는 경험을 통해 이것을 구분하는 쉬운 방법을 생각해냈다.
watch
는 "부수 효과" 처리를 위한 것이다. 만약 상태를 변경하고 싶다면 computed
를 사용하는 것이 좋다.
"부수 효과"는 컴포넌트 외부의 동작이나 비동기 처리를 말한다.
일반적인 예는 다음과 같다.
이 중 어떤 것도 직접 컴포넌트에 영향을 주지 않으므로 "부수 효과"로 간주한다.
만약 이런 "부수 효과"에 대한 일이 아니면, 아마 computed
을 사용하는 것이 맞을 것이다. computed
는 다른 변화에 대한 응답으로 계산을 업데이트해야 할 때 정말 좋다.
하지만 data
를 업데이트 하기 위해 watch
를 사용해야 하는 경우도 있다.
때로는 computed
를 사용하는 것이 의미가 없는 경우도 있다. <template>
이나 메서드에서 업데이트해야 한다면, 당신의 data
안으로 들어가야 한다. 그러나 그 후의 속성 변경에 대한 응답으로 업데이트 해야 하는 경우 watch
를 사용해야 한다.
주의: watch
를 사용하여 상태를 업데이트하려는 경우 주의해야 한다. 컴포넌트와 상위 컴포넌트가 같은 상태로 (직접 또는 간접적으로) 업데이트되고 있음을 의미한다. 매우 빠르게 이상해질 수 있다.
watch
하기 - 배열 또는 객체그럼, 실제로 watch
가 필요한 경우라고 가정해보자.
그러나 배열이나 객체를 watch
할 때, 예상했던 대로 동작하지 않는다.
무슨 일이 벌어지고 있는 거지?
몇가지 값이 포함된 배열을 만든다고 가정해 보자.
const array = [1, 2, 3, 4];
// array = [1, 2, 3, 4]
이제 더 많은 값을 넣어 배열을 업데이트하자.
array.push(5);
array.push(6);
array.push(7);
// array = [1, 2, 3, 4, 5, 6, 7]
질문이 있다. array
가 변경되었는가?
글쎄, 그렇게 간단하지 않다.
배열의 내용은 변경되었지만, 변수는 여전히 같은 array
객체를 가리킨다. 배열 컨테이너는 변경되지 않았지만 배열 내부는 변경되었다.
따라서 Vue는 배열이나 객체를 watch
할 때, 속성 내부가 변경되었다고 생각하지 않는다. Vue에게 변경을 watch
할 때 속성 내부를 검사하길 원한다고 알려줘야 한다.
다음과 같이 deep
을 true
로 설정하고 handler
메서드를 재배치 함으로써 Vue에게 원하는 바를 알려줄 수 있다.
export default {
name: 'ColourChange',
props: {
colours: {
type: Array,
required: true,
},
},
watch: {
colours: {
// This will let Vue know to look inside the array
deep: true,
// We have to move our method to a handler field
handler()
console.log('The list of colours has changed!');
}
}
}
}
이제 Vue는 변경 사항을 watch
할 때 속성 내부의 내용을 추적해야 함을 알 것이다.
그런데 handler 함수는 무엇일까?
조금 후에 handler에 대해 알아볼 것이다. 그 보다 우선 더 중요한 watch
의 immediate에 대해 알아보자.
watch
는 속성의 값이 변할 때 실행되지만, 종종 변경과 관계없이 처음 한 번 실행해야 하는 경우가 있다.
다음은 movie
속성의 설정에 따라 서버에서 데이터를 가져오는 MovieData
컴포넌트 예제이다.
export default {
name: 'MovieData',
props: {
movie: {
type: String,
required: true,
}
},
data() {
return {
movieData: {},
}
},
watch: {
// Whenever the movie prop changes, fetch new data
movie(movie) {
// Fetch data about the movie
fetch(`/${movie}`).then((data) => {
this.movieData = data;
});
}
}
}
이 컴포넌트는 훌륭하게 작동한다. movie
속성이 변경할 때마다 watch
가 실행되고 새로운 데이터를 가져온다.
여기에 작은 문제가 있다는 것만 빼고는 잘 동작한다.
문제는 페이지가 로드 될 때 movie
가 기본값으로 설정된다는 것이다. 그러나 속성이 아직 변경되지 않았으므로 watch
는 실행되지 않는다. 다른 동영상을 선택할 때까지 데이터가 로드되지 않음을 의미한다.
그렇다면 페이지 로드 시 즉시 watch
가 실행되도록 할 수 있을까?
immediate
를 true
로 설정하고 핸들러 함수를 아래처럼 옮긴다.
watch: {
// Whenever the movie prop changes, fetch new data
movie: {
// Will fire as soon as the component is created
immediate: true,
handler(movie) {
// Fetch data about the movie
fetch(`/${movie}`).then((data) => {
this.movieData = data;
});
}
}
}
자, 여러분은 handler
함수를 두 번이나 보았다. 이제 그게 무엇인지 다룰 때가 되었다.
Vue의 watch
에게 세 가지 속성을 지정할 수 있다.
처음 두 가지는 이미 보았고, 세 번째도 그리 어렵지 않다. 아마 당신도 모르게 벌써 사용하고 있었을 것이다.
handler
는 watch
된 속성이 변경될 때 호출될 함수를 지정한다.
우리가 흔히 보았던 코드는 deep
, immediate
를 지정할 필요가 없는 경우 사용하는 단축표현이다. 단축표현 대신 아래처럼 사용할 수 있다.
watch: {
movie: {
handler(movie) {
// Fetch data about the movie
fetch(`/${movie}`).then((data) => {
this.movieData = data;
});
}
}
}
단축표현을 사용하여 아래처럼 함수를 직접 지정할 수 있다.
watch: {
movie(movie) {
// Fetch data about the movie
fetch(`/${movie}`).then((data) => {
this.movieData = data;
});
}
}
Vue의 멋진 점은 함수를 처리하는 메서드 이름을 문자열로 지정할 수 있는 것이다. 두 개 이상의 속성이 변경될 때의 처리에 유용하다.
기존 예제에서 actor
속성과 함께 movie
속성도 사용하여 데이터를 가져와 보자. 메서드와 watch
는 아래와 같은 모습일 것이다.
watch: {
// Whenever the movie prop changes, fetch new data
movie {
handler: 'fetchData'
},
// Whenever the actor changes, we'll call the same method
actor: {
handler: 'fetchData',
}
},
methods: {
// Fetch data about the movie
fetchData() {
fetch(`/${this.movie}/${this.actor}`).then((data) => {
this.movieData = data;
});
}
}
이와 같이 사용하면 여러 속성이 같은 "부수 효과"를 일으킬 때, 코드를 좀 더 깔끔하게 해준다.