자식 컴포넌트 2개의 데이터를 비동기로 호출하는데 이 때 두 컴포넌트 모두 데이터가 존재하지 않다면, emit
을 통해 데이터 존재 여부를 상위 컴포넌트로 전달해주고, 상위 컴포넌트의 렌더링을 막으려고 했다.
// Parent.vue
<template>
<div v-if="isFristData || isSecondData">
<FirstChild @is-first-data="isFirstData" />
<SecondChild @is-second-data="isSecondData" />
</div>
</template>
<script>
export default {
name: "Parent",
methods: {
isFirstData(isShow) {
return isShow;
},
isSecondData(isShow) {
return isShow;
}
}
}
</script>
// FirstChild.vue
<template>
<div>FirstChild</div>
</template>
<script>
export default {
name: "Parent",
emits: ["isFirstData"],
created() {
this.getData();
},
methods: {
async getData() {
const res = axios.get('data api 요청');
this.$emit('isFristData', res);
}
}
}
</script>
// SecondChild.vue
<template>
<div>SecondChild</div>
</template>
<script>
export default {
name: "Parent",
emits: ["isSecondData"],
created() {
this.getData();
},
methods: {
async getData() {
const res = axios.get('data api 요청');
this.$emit('isSecondData', res);
}
}
}
</script>
FirstChild와 SecondChild의 data 존재 여부와 상관없이 Parent는 렌더링되지 않는다. 렌더링에 조건이 걸리지 않는 것으로 보아 동작 순서에서 문제가 있다는 추측을 할 수 있다.
내가 헷갈리는 부분은 beforeUpdate 전까지이므로 거기까지만 알아보겠다.
console.log를 찍어보면 created는 부모 → 자식 순, mounted는 자식 → 부모 순인 것을 알 수 있다.
vue의 생명주기에 따른 함수 실행은 동기적으로 실행된다. 즉, 자식의 created에서 비동기를 실행하여도 부모의 생명주기가 전부 실행된 후, 비동기 로직이 실행 컨텍스트 큐에 도달한다.
결국 emit으로 data의 유무 전달 시 부모 컴포넌트의 렌더링이 제대로 동작하지 않았던 이유는 isFirstData, isSecondData 모두 undefined가 들어가고 Parent 컴포넌트의 렌더링 조건이 false로 끝나고 나서야 비동기 로직의 emit이 실행되는 것이다.
emit으로 v-if의 렌더링 조건을 반영하기 위해서는 부모 컴포넌트에 렌더링 조건을 담당하는 data를 선언하고, emit으로 그 data 값을 변경해주면 다시 렌더링이 되면서 v-if에 렌더링 조건이 반영된다.
// Parent.vue
<template>
<div v-if="isFristData || isSecondData">
<FirstChild @get-first-data="getFirstData" />
<SecondChild @is-second-data="isSecondData" />
</div>
</template>
<script>
export default {
name: "Parent",
data() {
return {
isFristData: true,
isSecondData: true
}
}
methods: {
getFirstData(isShow) {
this.isFirstData = isShow;
},
getSecondData(isShow) {
this.isSecondData = isShow;
}
}
}
</script>
// FirstChild.vue
<template>
<div>FirstChild</div>
</template>
<script>
export default {
name: "Parent",
emits: ["getFirstData"],
created() {
this.getData();
},
methods: {
async getData() {
const res = axios.get('data api 요청');
this.$emit('getFristData', res);
}
}
}
</script>
// SecondChild.vue
<template>
<div>SecondChild</div>
</template>
<script>
export default {
name: "Parent",
emits: ["getSecondData"],
created() {
this.getData();
},
methods: {
async getData() {
const res = axios.get('data api 요청');
this.$emit('getSecondData', res);
}
}
}
</script>