인프런 커뮤니티 질문&답변

슬프구나님의 프로필 이미지
슬프구나

작성한 질문수

Typescript with Vue 실전 프로젝트

@Watch로 데이터 변화 감지하기

@Watch 질문 드립니다!

작성

·

502

1

안녕하세요? watch 속성 질문 드립니다.

 

<div>
<p>
@Watch
</p>
<button @click="changeMessage">메세지 변경</button>
<div>{{cMsg}}</div>
</div>

 

import { Component, Vue, Watch } from 'vue-property-decorator';
export default class Home extends Vue {
public message: string = 'hello children';
public cMsg: string | undefined;
public alertMsg: string = '변경이 감지되었습니다.';

// immediate : 즉시 호출하겠다는 의미.
// deep : object 내의 속성값까지 감시.
// @Watch('cMsg', {immediate: true, deep: true})
@Watch('cMsg')
public watchAlertMsg(value: string | undefined, oldValue: string | undefined) {
console.log(value);
console.log(oldValue);
alert(this.alertMsg);
}

public changeMessage() {
this.cMsg = 'change';
}

}

 

위와 같이 코딩을 했는데, 

cMsg 상태변수에 '' 이런식으로 초기화를 해둔경우는 정상적으로 동작을 하는데,

위와 같이 하면 왜 변경감지가 안되는지 알고싶습니다.

TS를 사용안한 vue에서는 테스트를 해보지는 못했습니다..ㄷㄷ

 

public cMsg: string | undefined = '';

위와 같이 초기화를 해주면,

옆에 사진과 같이, 해당 컴포넌트 상태변수로 존재합니다. 

= ''; 구문을 빼면, 상태변수 자체도 안보이구요

 

제가 TS구문을 잘 몰라서 이런거 같기는 한데.. 

public cMsg: string | undefined

해당 상태변수에 문자열 또는 undefined 가 할당이 될수 있어 이거 아닌가요? 그러면 제 생각은

cMsg = undefined; 이런거니 여기서 값이 바뀌면 감지가 되야 하는거같은데..ㅠㅠ 어렵네요

 
 
watch: {
testWatch(after, before) {
console.log('감지?');
console.log(before);
console.log(after);
}
},

data() {
return {
testWatch : undefined,
};
}

위 와 같이 하면, 정상적으로 감지(값을 변경할때마다)가 되어서 watch 속성 콜백함수가 호출이 됩니다.

TS 당신은 왜..ㅠㅠ

답변 2

1

성도희님의 프로필 이미지
성도희
지식공유자

안녕하세요! ChangHyeon Bae님!

Watch는 데이터의 변경을 관찰합니다.

질문 주신 케이스에서 Watch가 동작하지 않는 이유는,
cMsg라는 속성이 없기 때문입니다. 없는 속성에 Watch를 설정해놓은 것과 마찬가지지요.

public cMsg: string | undefined ;

위와 같이 분명히 선언했는데 왜 없을까요?

그 이유는, vue-cli로 코드를 빌드하면, webpack과 ts-loader로
타입스크립트 문법을 자바스크립트로 컴파일을 하게 됩니다.
이 때 프로퍼티를 확인해서 값이 할당된 프로퍼티만 객체의 속성으로 추가하기 때문입니다.

public cMsg: string | undefined = undefined;

또한 위와 같은 코드도 동일하게 동작하지 않습니다.

Vue 공식 문서에서 아래와 같이 설명하고 있습니다.

"Vue는 루트 수준의 반응성 속성을 동적으로 추가 할 수 없으므로
모든 루트 수준의 반응성 데이터 속성을 빈 값으로라도 초기에 선언하여 Vue 인스턴스를 초기화해야합니다."

export default class Home extends Vue {
public cMsg: string | undefined;

created() {
// undefined;
console.log(this);
}
}

위와 같이 created hook에서 this를 콘솔로 출력해보면,
cMsg라는 속성은 없는것을 확인하실 수 있습니다.

그래서 이로인해 발생하는 문제점을 막기 위해 타입스크립트에서는
tsconfig.json에 특별한 설정을 하지 않거나, !를 붙이지 않은 클래스 프로퍼티에 대해서는
에러를 발생하고 있습니다.

@Prop과 같이 특수한 경우가 아닐때는 반드시 undefined가 아닌 값으로 초기화 해주시기 바랍니다.
(공통된 빈값이 필요한 경우에는 null을 사용하세요.)

참고로, changeMessage라는 메서드에서 값을 할당하고 있긴 하지만,
이 경우에는 값을 수정하는것이 아닌 속성을 "추가"하는 것입니다!

Vue의 Watch는 속성의 추가/제거에 대해 감지할 수 없는 한계를 가지고 있습니다.
(자세한 내용은 https://kr.vuejs.org/v2/guide/reactivity.html<- 링크를 방문하세요.)

0

슬프구나님의 프로필 이미지
슬프구나
질문자

친절한 답변 정말로 감사합니다!

결론은 data 옵션에 해당 상태변수 자체가 존재하지 않는 상태에서 watch를 걸어버린거네요 ㅠㅠ

 

그래도 여전히 읽어보면서 의문인건.

 

public cMsg: string | undefined = undefined;

TS로 초기화 해준 undefined와

 

<template>
<div>
<button @click="changeValue">
watch 감지!
</button>
</div>
</template>

<script>
export default {
name: "Watch",

watch : {
changeVal(value, oldValue) {
console.log('감지?');
console.log(value);
console.log(oldValue);
},
},

data(){
return {
changeVal : undefined
}
},

methods : {
changeValue() {
this.changeVal = Math.floor(Math.random() * 10) + 1; // 1 ~ 10 난수 생성
}
}
}
</script>

<style scoped>

</style>

SFC 방식으로 한, 이거에 동작 차이는 역시 아직도 의문이네요.

 

슬프구나님의 프로필 이미지
슬프구나

작성한 질문수

질문하기