728x90

vue를 사용함에 있어서 가장 짜증나는 부분은 바로 반응이 언제되는가이다.

왜냐하면 이를 모르면 여러분은 값을 변화를 주더라도 실제로는 반영되지 않는 경우가 많다.

가령 아래와 같은 코드를 보자.



코드가 기니까 조금 잘라서보자.


// session.js
export default {}

session은 그냥 빈객체다.


created() {
console.log(this)
this.instance = 0
},
data() {
return {
value: 0,
session
}
},

여러분은 현재 이 vue컴포넌트는 this로 호출할 수 있다는 것을 알 수 있다.

그럼 위 같은 코드가 존재할경우 this변수는 총 3가지가 있다.

instance, value, session이렇게 세종류가 있는데 이 셋은 작동하는 원리가 서로 다르다.

그 이유에 대해서 설명하기 전에 각각의 처한 상황을 보도록 하자.


value - data로 선언한 기본 변수

session - data로 선언한 object

instance - data로 선언하지 않은 기본 변수


이 셋의 구동원리는 다르다.


그럼먼저 예제를 한번 작동시켜보자.



여러분이 이 예제를 실행시켜본다면 value를 눌렀을때는 화면에 반영이 된다. 하지만 instance를 눌렀을 때는 반영이 되지 않는다.

또한 session역시 값을 추가할 경우 값이 변동되지 않는다.

하지만 갑자기 value를 누르면 값이 변동된다.


이 이유는 뭘까??

vue에서 data에 변수선언하는건 단순히 data 탭에 변수를 선언하는데서 끝나는게 아니다.

이 data에서 변수선언은 "난 data의 변동을 추적하겠다."라고 선언하는 것과 같다.

더 자세한 설명은 딱히 하지 않을 생각이지만 어떤 현상이 일어나는지는 볼 필요가 있다.



데이터를 출력해보면 실제로 session과 instance, value모두 값이 만들어졌다는걸 알 수 있다.


다만 session과 value는 data에도 변수가 들어있다.


그리고 아래 보면 value와 session은 getter와 setter가 생성된걸 확인할 수 있다.


data에 선언하면 Object.defineProperty를 사용해서 getter와 setter를 만들게 되고

이 getter와 setter에 추적 코드를 끼워넣는다.


그러면 이를 watcher라는 녀석이 계속해서 감시하며 변동사항이 있으면 이를 반영하게 된다.

정말 다행이게도 이 watcher라는 녀석이 감지하지 못하는 변수도 화면에 재렌더링은 하게 된다.

왜냐하면 여러분이 vue구문을 사용해서 (예를 들마면 v-bind나 {{}})선언한 변수들은

변수가 바뀌면 다시 바뀐값을 집어 넣는다.

문제는 data에 선언한 변수가 아니라면 이 바뀐타이밍 자체를 모르기 때문에

나중에 바뀐녀석이 바뀔때 일괄적용이 되게 된다. 그래서 여러분이 변동을 추적하기 위해서는 반드시 data로 선언한다.

이제 여러분인 instance가 왜 변동이 안되고 value가 변동될때 일괄 변동되는지 알 수 있다.


근데 문제는 object녀석이다.


session은 data로 선언했음에도 불구하고 왜 바뀌지 않는걸까?

이 역시 간단한데 session자체는 바뀌기 않았기 떄문이다.

session은 안바뀌고 session내부가 바뀐것이다.

이 바뀐것은 추적할 수 없다.


이는 object뿐만아니라 array역시 마찬가지이다.


그러면 해결법은 두개로 요약된다.


1.object나 array를 변동시킨다.

2.아니면 다른 제공된 방식을 사용한다.


<template>
<div id="app">
{{session}}<br>
<input type="button" value="session add" @click="onclicks"><br>
</div>
</template>

<script>
import session from './js/session.js'

let i = 0;
let j = 10;

export default {
name: 'app',
components: {},
created() {
},
data() {
return {
session
}
},
methods: {
onclicks() {
this.session[i++ + 'hi'] = j++ + 'hi'
this.session = Object.assign({}, this.session)
},
}
}
</script>

<style>

</style>

1번방식으로 다른 Object를 붙히는 방식이다.

그러기위해서 Object.assign을 사용한다. 이 방식은 객체의 크기가 작을 때는 별 문제가 없다.

하지만 크다면 값의 복사가 빈번하게 일어나기 때문에 권장하는 방식은 아니다,


<template>
<div id="app">
{{session}}<br>
<input type="button" value="session add" @click="onclicks"><br>
</div>
</template>

<script>
import session from './js/session.js'

let i = 0;
let j = 10;

export default {
name: 'app',
components: {},
created() {
},
data() {
return {
session
}
},
methods: {
onclicks() {
this.$set(this.session,i++ + 'hi',j++ + 'hi')
},
}
}
</script>

<style>

</style>

this.$set(<object>,<key>,<value>)


또다른 방식은 this.$set을 사용하는것이다. 이는 vue에서 재공하는 방식인데 이 녀석을 호출하면 object나 array의 변동사항을 감지할 수 있다.



array의 경우 splice를 사용할 경우 추적할 수 있다. 거기에 대한 설명은 이 포스팅을 참조하는 것이 좋다.









+ Recent posts