본문 바로가기
Framework/vue_Architecture

부모, 자식간 데이터 전송 (vue.js)

by cariño 2022. 12. 25.
728x90
반응형

 

부모 컴포넌트로 값 보내기 : $emit
자식 컴포넌트로 값 전달: props

- 모든 props는 하위 속성과 상위 속성 사이의 단방향 바인딩을 형성한다. (상위 -> 하위만 됨)

- 부모 컴포넌트 속성에 넘겨줄 props를 선언한다. 

- 자식 컴포넌트의 script안에 props안에 데이터 타입(Sting, Array, Object...)을 명시해야 하고, 디폴트값을 설정 할 수 있다.

- lifecycle created(생성 시점)에 props로 넘어온 값이 자식 컴포넌트에도 생성 된다. 

 

 

Props 사용 방법

- 부모 컴포넌트에서 props선언

<template>
	<ChildComponent 자식 데이터="데이터" />
	<ChildComponent :자식 데이터="부모 데이터" />
</template>

 

- 자식 컴포넌트에서 props 정의

// 1. 데이터 타입
props: {
	프롭명: 데이터 타입 Only
}
// 2. 데이터 타입, 디폴트
props: {
	프롭명: {
    	type: 데이터 타입
        default: 디폴트 값
    }
}
// 3. 오브젝트 타입
props: {
 	프롭명: {
    	type: 데이터 타입
        default: () => {
          key1: value1,
          key2: value2, ...
        }
    }
}
// 4. 배열 타입 (ts 아님)
props: ['ddd', 'aaa']

 

 

예제)

<template>
    <Block v-if="isPlaying" :delay="delay" />
    <!--<Block v-if="isPlaying" :delay="" />-->
</template>

<script>
import Block from "./components/Block.vue";
export default {
    name: "App",
    components: { Block },
    data() {
        return {
            isPlaying: false,
            delay: null,
        };
    }
};
</script>

1. [부모 -> 자식 컴포넌트 props전달]

- 컴포넌트를 import 해오기

- components: { 자식 컴포넌트 입력 }

- template안에서 :v-bind를 통해 전달해주는 props입력 (:delay="delay")

- props이 빈 값인 경우 default가 적용된다. 

 

 

//Blcok.vue

<template>
    <div class="block" v-if="showBlock">click me</div>
</template>

<script>
export default {
    props: ["delay"],
    data() {
        return {
            showBlock: false,
            ...
        };
    },
}
</script>

2. [부모 -> 자식 컴포넌트 props 전달 받기]

전달 받은 prop은 자식 컴포넌트에서 직접 변경할 수 없다. 

 

emit 사용 방법

자식 컴포넌트에서 변경된 값 혹은 데이터를 부모 컴포넌트에 전달하려면 $emit속성을 사용해야 한다. 

이벤트를 전달함으로써 상위컴포넌트는 하위 컴포넌트에서 전달하는 값을 전달 받을 수 있다.

 

[flow]

- 부모 컴포넌트트 자식 컴포넌트로 prop을 전달한다. 

- 자식 컴포넌틑 전달 받은 prop을 가지고 메서드를 통해 수정된 값을 emit을 통해 부모 컴포넌트에게 전달해 준다. 

- 부모 컴포넌트는 emit을 통해 전달받은 값을 활용해 데이터를 업데이트를 한다. 

 

this.$emit("이벤트 명")

- emit을 호출할 때 사용하는 this는 하위 컴포넌트를 의미한다. 

- 첫번째 인자: 부모 컴포넌트에서 자식 컴포넌트를 호출할 때 사용하는 메서드 명

- 두번째 인자: 메서드에 들어갈 값

 

예제)

//자식 컴포넌트
<template>    
    <div class="block" v-if="showBlock" @click="stopTimer">click me</div>
</template>

<script>
export default {
	...
    methods: {
        stopTimer() {
            clearInterval(this.timer);
            this.$emit("end", this.reactionTime);
        },
    },
};
</script>

this.$emit("end", this.reactionTime);

end라는 이름으로 부모에게 해당 메소드를 전달한다. 

 

<template>
    <Block v-if="isPlaying" :delay="delay" @end="endGame" />
</template>

<script>
import Block from "./components/Block.vue";
export default {
    name: "App",
    components: { Block },
    data() {
        return {
            isPlaying: false,
            delay: null,
        };
    },
    methods: {
        endGame(reactionTime){
            this.isPlaying = false;
            this.showResults = true;
        },
    },
};
</script>

@end로 받은 this.reactionTime을 가지고 endGame 이란 methos를 사용한다. 

 

 


전체 코드 

 

[디렉토리 구조]

app.vue(부모 컴포넌트)

block.vue(자식컴포넌트)

result.vue(자식컴포넌트)

 

[구현하려는 기능]

block 컴포넌트에서 부모 컴포넌트에서 emit을 통해 데이터를 전달 받는다. 

전달 받은 데이터는 result 컴포넌트(또 다른 자식 컴포넌트)에게 전달한다. 

 

//block.vue

<template>
    <div class="block" v-if="showBlock" @click="stopTimer">click me</div>
</template>

<script>
export default {
    props: ["delay"],
    data() {
        return {
            showBlock: false,
            timer: null,
            reactionTime: 0,
        };
    },
    mounted() {
        setTimeout(() => {
            this.showBlock = true;
            this.startTimer();
        }, this.delay);
    },
    methods: {
        startTimer() {
            this.timer = setInterval(() => {
                this.reactionTime += 10;
            }, 10);
        },
        stopTimer() {
            clearInterval(this.timer);
            this.$emit("end", this.reactionTime);
        },
    },
};
</script>

 

 

//app.vue

<template>
    <h1>Ninja Reaction Timer</h1>
    <button @click="start" :disabled="isPlaying">play</button>
    <Block v-if="isPlaying" :delay="delay" @end="endGame" />
    <Results v-if="showResults" :score="score" />
</template>

<script>
import Block from "./components/Block.vue";
import Results from "./components/Results.vue";
export default {
    name: "App",
    components: { Block, Results },
    data() {
        return {
            isPlaying: false,
            delay: null,
            score: null,
            showResults: false,
        };
    },
    methods: {
        start() {
            this.delay = 2000 + Math.random() * 5000;
            this.isPlaying = true;
        },
        endGame(reactionTime) {
            this.score = reactionTime;
            this.isPlaying = false;
            this.showResults = true;
        },
    },
};
</script>

 

 

//Result.vue

<template>
    <p>reaction time: {{ score }}</p>
    <p class="rank">{{ rank }}</p>
</template>

<script>
export default {
    props: ["score"],
    data() {
        return {
            rank: null,
        };
    },
    mounted() {
        if (this.score < 250) {
            this.rank = " ninja fingers";
        } else if (this.score < 400) {
            this.rank = "rapid reflexes";
        } else {
            this.rank = "snail pace...";
        }
    },
};
</script>

<style>
.rank {
    font-size: 1.4em;
    color: orange;
    font-weight: bold;
}
</style>
728x90

'Framework > vue_Architecture' 카테고리의 다른 글

Composition API: ref() vs reactive()  (0) 2023.01.02
Vue Router(1)  (0) 2023.01.02
composition API(1)_반응성(vue3.js)  (1) 2022.12.30
fetching data (vue.js)  (0) 2022.12.26
데이터 양방향 바인딩 (vue.js)  (0) 2022.12.25

댓글