vue의 컴포넌트 렌더링 순서를 확실히 알아보자!

박재현·2022년 12월 16일
0

FE 톺아보기

목록 보기
10/10
post-thumbnail

🤔이슈 정의

자식 컴포넌트 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는 렌더링되지 않는다. 렌더링에 조건이 걸리지 않는 것으로 보아 동작 순서에서 문제가 있다는 추측을 할 수 있다.

vue의 생명주기

내가 헷갈리는 부분은 beforeUpdate 전까지이므로 거기까지만 알아보겠다.

  • data, computed, methods, watch 등 정의 → created -> 인스턴스 부착 → beforeMount → 렌더링 → mounted

부모 자식 간 렌더링 순서

console.log를 찍어보면 created는 부모 → 자식 순, mounted는 자식 → 부모 순인 것을 알 수 있다.

  • 부모 data 등 정의 → 부모 created → 자식 data 등 정의 → 자식 created → 자식 렌더링 → 자식 mounted → 부모 렌더링 → 부모 mounted

컴포넌트의 동기적 실행

vue의 생명주기에 따른 함수 실행은 동기적으로 실행된다. 즉, 자식의 created에서 비동기를 실행하여도 부모의 생명주기가 전부 실행된 후, 비동기 로직이 실행 컨텍스트 큐에 도달한다.

🏆trouble shooting

결국 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>
profile
공동의 성장을 추구하는 개발자

0개의 댓글