뷰 공부 도중 알게 된 사실이나 모호한 부분에 대한 정리를 위한 포스트입니다.
computed 의 경우 화면에서 시작된 기능이 아닌 경우 변경이 감지되지 않는 특이사항을 발견함.
vue - 2.7.10
nuxt - 2.15.8
vuetify - 2.6.10
// store/index.js
export default {
state() {
return {
testState: '',
};
},
mutations: {
setTestState(state, payload) {
state.testState = payload.testState;
},
},
actions: {
testStateAction(context, payload) {
context.commit('setTestState', payload);
},
},
};
// page.vue 내 computed 영역
computed: {
isTestState() {
console.log('computed isTestState time: ' + new Date());
return !!this.$store.state.testState;
},
},
참고) 화면 스크롤 기능은 computed 기능과는 전혀 관련이 없습니다.
이와 비슷하지만 캐싱없이 항상 호출되는 watch 는 어떻게 동작하는지 확인함.
0. 테스트 코드
// store/index.js
export default {
state() {
return {
testState: '',
};
},
mutations: {
setTestState(state, payload) {
state.testState = payload.testState;
},
},
actions: {
testStateAction(context, payload) {
context.commit('setTestState', payload);
},
},
};
// page.vue 내 data 영역
data() {
return {
testStateWatch: false,
};
},
// page.vue 내 watch 영역
watch: {
'$store.state.testState'(value) {
this.testStateWatch = !!value;
console.log(`testState value: ${value}, watch time: + ${new Date()}`);
},
},
화면 초기 watch 관련 값 확인
watch 관련 값 false 확인, watch 는 최초 화면 진입이라 동작하지 않음.
watch 관련값 변경 및 확인
관련 값 변경 후 바로 호출되어 timeMillis 가 거의 일치함.
watch 관련 값 변경 -> watch 호출 -> 변경 완료 후 callback 동작
watch 의 경우 값이 변경되면 바로 호출됨을 확인함.
그렇다면 watch 와 computed 를 같이 사용할 경우 어떨지 확인함.
0. 테스트 코드
// store/index.js
export default {
state() {
return {
testState: '',
};
},
mutations: {
setTestState(state, payload) {
state.testState = payload.testState;
},
},
actions: {
testStateAction(context, payload) {
context.commit('setTestState', payload);
},
},
};
// page.vue 내 computed 영역
computed: {
isTestState() {
console.log('computed isTestState time: ' + new Date());
return !!this.$store.state.testState;
},
// page.vue 내 watch 영역
watch: {
'$store.state.testState'(value) {
// watch 호출확인을 위해 로그만 기록함.
console.log(`testState value: ${value}, watch time: + ${new Date()}`);
},
},
화면 초기 watch, computed 관련 값 확인
computed 호출 확인, computed 초기값 false 확인
watch, computed 관련 값 변경 및 확인
testState 변경 -> watch 호출 -> state 변경 콜백 -> computed 호출 확인
watch 감지 후 약간의 딜레이 후 computed 가 호출된다.(밀리초 이내)
v-app-bar
엘리먼트(vuetify 컴포넌트)에서 update 이벤트를 발생시키는 것을 확인함.그렇다면 vue 의 lifecycle 내에서 computed 관련 값을 변경하는 경우에는 감지하는지 확인
테스트는 methods 영역, watch 영역에서 각각 변경하는 케이스로 확인함.
0. 테스트 코드
// store/index.js
export default {
state() {
return {
testState: '',
};
},
mutations: {
setTestState(state, payload) {
state.testState = payload.testState;
},
},
actions: {
testStateAction(context, payload) {
context.commit('setTestState', payload);
},
},
};
// page.vue 내 method 호출 버튼, watch 감지 스위치
<v-btn style="margin-right: 10px" depressed @click="changeTestState"
>testState 변경</v-btn
>
<v-btn style="margin-right: 10px" depressed @click="changeTestState"
>testState 변경</v-btn
>
// page.vue 내 computed 영역
computed: {
isTestState() {
console.log('computed isTestState time: ' + new Date());
return !!this.$store.state.testState;
},
},
// page.vue 내 data 영역
data() {
return {
watchTestState: false,
};
},
// page.vue 내 watch 영역
watch: {
watchTestState() {
const testState = this.$store.state.testState === '' ? 'abc' : '';
const payload = { testState };
this.$store.dispatch('testStateAction', payload);
console.log(`watchTestState time: ${new Date()}`);
},
}
// page.vue 내 methods 영역 changeTestState 메소드
methods:{
changeTestState() {
const testState = this.$store.state.testState === '' ? 'abc' : '';
const payload = { testState };
this.$store.dispatch('testStateAction', payload);
console.log(`changeTestState time: ${new Date()}`);
},
}
화면 초기 computed 관련 값 확인
watch 영역에서 관련 값을 변경하는 경우
store 영역의 데이터를 기준으로 테스트했기에 보편적인 data 영역의 변수를 기준으로 테스트도 해봐야되지 않을까 싶다.
websocket 1.0.34
webstomp-client 1.2.6
disconnect 시, setTimeout 0 초로 내부적으로 값을 한번 더 변경한다.
이로 인해 store 영역에서 사용 시, disconnect 된 stompClient 값이 state 에 할당된 이후 한번 더 값의 변경이 발생하여 아래 오류가 발생한다.
이를 해결하기 위해 state 에 할당하는 시간을 setTimeout 0 으로 값의 변경 이후 동작하도록 수정하여 문제를 해결함
// store.js 의 actions 영역
disconnect({ state, commit }) {
if (!state.stompClient?.connected) {
const e = new Error('소켓이 연결되지 않았습니다.');
throw e;
}
const stompClient = _.cloneDeep(state.stompClient);
stompClient.disconnect(() =>
setTimeout(() => commit('setStompClient', stompClient), 0),
);
},
setTimeout 인 점을 확인하고 문제를 해결했으나, 기존에 알던 setTimeout(callback, timeMillis)
와 문법이 달라서 다소 헷갈렸다.
또한 setTimeout 0초이지만 이는 이벤트루프를 통해 동작하므로 비동기로 처리되게 된다는 점도 새롭게 배울 수 있었다.
이후 생성된 소켓클라이언트로 메시지 통신해본 결과
SockJs 를 래핑한 WebStomp 내부함수 send() 에서 내부 변수를 조작하는 것을 확인되었다.
위 2가지 문제점을 고려하여 store 영역에서 stompclient 를 관리하는 방안은 폐기하는 것이 맞을듯 하다.
// 기존 Option API 방식
// -> 테이블에 데이터를 넣고 정제하는 로직이 하나의 기능임에도 분리되어있어 관리포인트가 늘어남.
export default {
data() {
return {
table: [],
};
},
methods: {
addRow(row) {
this.table.push(row);
},
},
computed: {
filteredTable() {
return this.table.filter(row => !!row);
},
}
}
// Vue3 기준 Composition API -> 영역 구분없이 한데모아 관리가 가능함.
<script setup>
const table = ref([]);
const addRow = row => table.value.push(row);
const filteredTable = computed(() => table.value.filter(row => !row));
</script>
잘 봤습니다. 좋은 글 감사합니다.