[MyLeague:bug] 자식 컴포넌트 렌더링시 부모의 일부데이터가 props로 넘어오지 않는 문제
문제상황
Standing.vue
<script>
export default {
props: {
participants: Array,
round: Number,
},
data() {
return {
records: [],
}
},
mounted() {
this.participants.forEach(participant => {
let newRecord = {
team: null,
record: null,
};
newRecord.team = participant.team;
newRecord.record = participant.records.filter(r => r.round === this.round)[0];
});
},
watch: {
participants() {
console.log("change");
}
}
}
</script>
<template>
<!-- 순위를 만드는 코드...(생략) -->
</template>
LeagueShow.vue
<script>
export default {
data() {
return {
participants: [],
}
},
async mounted() {
const res = await this.axios.get(`/participants`);
this.participants = res.data.content;
this.participants.forEach(async (participant) => {
const res_record = await this.axios.get(this.getLink(participant.links, "record"));
participant.record = res_record.data;
const res_team = await this.axios.get(this.getLink(participant.links, "team"));
participant.team = res_team.data;
});
}
}
</script>
<template>
<Standing :participants="participants" :round="1" />
</template>
LeagueShow.vue는 리그에 대한 전체 정보를 보여주는 컴포넌트이다. 이때 리그 전체 순위를 보여주기 위해 Standing.vue 컴포넌트를 import해서 렌더링하게 된다.(순위표를 보여주는 부분만 남기고 나머지는 생략) 이때 Standing은 LeageShow의 data인 participant(리그 참가팀에 대한 정보)를 props로 받게 된다. 그후 mounting시점에 participant 데이터를 파싱해서 record에 저장한다.
Bug
props로 넘어온 participant의 데이터가 부족한 문제가 발생하였다.
원인
컴포넌트는 자신들의 마운팅 시점의 mounted()를 실행하고, 마운팅이 된 이후에야 페이지가 렌더링되게 된다. 그러므로 mounted()에서 실행하는 participant를 가져오는 동작이 모두 수행된 다음에 LeagueShow의 자식 컴포넌트인 Standing컴포넌트를 렌더링 할것이라 예상할 수 있다. 하지만 문제는 Particpant 데이터를 데이터베이스에서 가져오는 과정이 비동기적으로 실행된다는 것이다. 즉, 프로그램은 해당 메서드를 실행하고 넘겨버린다. 즉, participant 데이터가 다 로드되지 않은 시점에 페이지가 렌더링 될 수 있는 것이다.
해결
해결방법은 간단하다. 비동기적으로 로딩받는 데이터가 필요한 컴포넌트는 해당 데이터가 다 들어왔는지 점검하고 페이지를 렌더링하는 것이다. v-if를 사용하면 쉽게 구현할 수 있다.
<Standing v-if="participants.length > 0" :participants="participants" :round="1" />
다음과 같이 participants에 어떤 데이터가 들어왔을 경우에만 해당 컴포넌트를 렌더링 한다.
아래 링크는 비슷한 문제를 다룬 stackoverflow 게시물이다.
vue js 2: Access props in mounted function
I have data props in child components. Inside child component on mounted function I need to get specific value from props and set select dropdown value. I am using vue-multiselect plugin which is w...
stackoverflow.com