부모 컴포넌트로 값 보내기 : $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>
'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 |
댓글