커뮤니케이션 유형
Vue 응용 프로그램 (또는 실제로 모든 구성 요소 기반 응용 프로그램)을 디자인 할 때 우리가 처리하는 문제에 따라 다른 통신 유형이 있으며 고유 한 통신 채널이 있습니다.
비즈니스 로직 : 앱과 그 목표와 관련된 모든 것을 나타냅니다.
프리젠 테이션 로직 : 사용자가 상호 작용하거나 사용자의 상호 작용으로 인해 발생하는 모든 것.
이 두 가지 문제는 다음 유형의 의사 소통과 관련이 있습니다.
각 유형은 올바른 통신 채널을 사용해야합니다.
커뮤니케이션 채널
채널은 Vue 앱 주변에서 데이터를 교환하기 위해 구체적인 구현을 참조하는 데 사용할 느슨한 용어입니다.
소품 : 부모-자식 프레젠테이션 논리
직접 부모-자녀 커뮤니케이션을 위한 Vue의 가장 간단한 커뮤니케이션 채널입니다 . 주로 프리젠 테이션 논리 또는 제한된 데이터 집합과 관련된 데이터를 계층 구조 아래로 전달하는 데 사용해야합니다.
참조 및 방법 : 프레젠테이션 안티 패턴
자식이 부모의 이벤트를 처리하도록 소품을 사용하는 것이 이치에 맞지 않을 때 자식 구성 요소에를 설정하고 ref
해당 메서드를 호출하는 것이 좋습니다.
그러지 마세요, 안티 패턴입니다. 구성 요소 아키텍처 및 데이터 흐름을 재고하십시오. 부모의 자식 구성 요소에 대한 메서드를 호출하려는 경우 상태를 높이 거나 여기 또는 다른 답변에 설명 된 다른 방법을 고려할 때입니다.
이벤트 : 자식-부모 프레젠테이션 논리
$emit
및 $on
. 직접적인 자녀-부모 의사 소통을위한 가장 간단한 의사 소통 채널. 다시 말하지만, 표현 로직에 사용되어야합니다.
이벤트 버스
대부분의 답변은 멀리 떨어진 구성 요소 또는 실제로 사용할 수있는 통신 채널 중 하나 인 이벤트 버스에 대한 좋은 대안을 제공합니다.
이 기능은 그 사이에 필요한 다른 컴포넌트가 거의없는 상태에서 아래로 깊숙이 중첩 된 하위 컴포넌트로 소품을 사방에 전달할 때 유용 할 수 있습니다. 신중하게 선택한 데이터에 대해서는 조금만 사용하십시오.
주의 : 이벤트 버스에 자신을 바인딩하는 구성 요소의 후속 생성은 두 번 이상 바인딩되어 여러 처리기가 트리거되고 누수가 발생합니다. 개인적으로 과거에 디자인 한 모든 단일 페이지 앱에서 이벤트 버스의 필요성을 느끼지 못했습니다.
다음 Item
은 DOM에서 제거 된 경우에도 구성 요소가 계속 트리거 되는 간단한 실수로 인해 누출이 발생하는 방법을 보여줍니다 .
// A component that binds to a custom 'update' event.
var Item = {
template: `<li>{{text}}</li>`,
props: {
text: Number
},
mounted() {
this.$root.$on('update', () => {
console.log(this.text, 'is still alive');
});
},
};
// Component that emits events
var List = new Vue({
el: '#app',
components: {
Item
},
data: {
items: [1, 2, 3, 4]
},
updated() {
this.$root.$emit('update');
},
methods: {
onRemove() {
console.log('slice');
this.items = this.items.slice(0, -1);
}
}
});
<script src="https://unpkg.com/vue@2.5.17/dist/vue.min.js"></script>
<div id="app">
<button type="button" @click="onRemove">Remove</button>
<ul>
<item v-for="item in items" :key="item" :text="item"></item>
</ul>
</div>
destroyed
라이프 사이클 후크 에서 리스너를 제거하는 것을 잊지 마십시오.
중앙 집중식 저장소 (비즈니스 로직)
Vuex 는 상태 관리를 위해 Vue를 사용하는 방법 입니다. 이벤트 이상을 제공하며 본격적인 적용을위한 준비가되어 있습니다.
이제 묻습니다 .
사소한 커뮤니케이션마다 vuex 스토어를 만들어야하나요?
다음과 같은 경우에 정말 빛납니다.
- 비즈니스 로직을 다루고,
- 백엔드 (또는 로컬 저장소와 같은 데이터 지속성 레이어)와 통신
따라서 구성 요소는 사용자 인터페이스를 관리하는 원래 의도에 집중할 수 있습니다.
구성 요소 논리에 사용할 수 없다는 의미는 아니지만 필요한 전역 UI 상태 만있는 네임 스페이스가있는 Vuex 모듈로 해당 논리의 범위를 지정합니다.
전역 상태의 모든 것을 처리하지 않으려면 저장소를 여러 네임 스페이스 모듈로 분리해야합니다.
구성 요소 유형
이러한 모든 통신을 조율하고 재사용을 용이하게하려면 구성 요소를 두 가지 유형으로 생각해야합니다.
다시 말하지만, 일반 구성 요소를 재사용해야하거나 앱 특정 컨테이너를 재사용 할 수 없다는 의미는 아니지만 책임이 다릅니다.
앱별 컨테이너
이들은 다른 Vue 구성 요소 (일반 또는 기타 앱 특정 컨테이너)를 래핑하는 단순한 Vue 구성 요소입니다. 여기서 Vuex 스토어 통신이 발생하고이 컨테이너는 소품 및 이벤트 리스너와 같은 다른 간단한 수단을 통해 통신해야합니다.
이러한 컨테이너에는 기본 DOM 요소가 전혀 없을 수도 있으며 일반 구성 요소가 템플릿 및 사용자 상호 작용을 처리 할 수 있습니다.
범위를 어떻게 든 events
또는 stores
형제 자매 구성 요소에 대한 가시성
여기에서 범위 지정이 발생합니다. 대부분의 구성 요소는 상점에 대해 알고하지 않으며,이 구성 요소는 (대부분) 사용 하나의 제한된으로 저장 모듈을 네임 스페이스해야 getters
하고 actions
제공된 적용 Vuex 바인딩 도우미 .
일반 구성 요소
이들은 소품에서 데이터를 수신하고, 자체 로컬 데이터를 변경하고, 간단한 이벤트를 생성해야합니다. 대부분의 경우 그들은 Vuex 스토어가 존재한다는 사실을 전혀 몰라 야합니다.
다른 UI 구성 요소에 대한 유일한 책임이있을 수 있으므로 컨테이너라고도합니다.
형제 커뮤니케이션
그렇다면이 모든 과정에서 두 형제 구성 요소간에 어떻게 통신해야합니까?
예를 들어 이해하기가 더 쉽습니다. 입력 상자가 있고 그 데이터가 앱 전체 (트리의 다른 위치에있는 형제)에서 공유되고 백엔드와 유지되어야한다고 가정합니다.
최악의 시나리오 부터 시작하여 구성 요소는 프레젠테이션 과 비즈니스 로직을 혼합 합니다 .
// MyInput.vue
<template>
<div class="my-input">
<label>Data</label>
<input type="text"
:value="value"
:input="onChange($event.target.value)">
</div>
</template>
<script>
import axios from 'axios';
export default {
data() {
return {
value: "",
};
},
mounted() {
this.$root.$on('sync', data => {
this.value = data.myServerValue;
});
},
methods: {
onChange(value) {
this.value = value;
axios.post('http://example.com/api/update', {
myServerValue: value
})
.then((response) => {
this.$root.$emit('update', response.data);
});
}
}
}
</script>
이 두 가지 문제를 분리하려면 컴포넌트를 앱 특정 컨테이너에 래핑하고 프레젠테이션 로직을 일반 입력 컴포넌트에 유지해야합니다.
우리의 입력 구성 요소는 이제 재사용 가능하며 백엔드 나 형제에 대해 알지 못합니다.
// MyInput.vue
// the template is the same as above
<script>
export default {
props: {
initial: {
type: String,
default: ""
}
},
data() {
return {
value: this.initial,
};
},
methods: {
onChange(value) {
this.value = value;
this.$emit('change', value);
}
}
}
</script>
이제 앱별 컨테이너가 비즈니스 로직과 프레젠테이션 커뮤니케이션 사이의 다리가 될 수 있습니다.
// MyAppCard.vue
<template>
<div class="container">
<card-body>
<my-input :initial="serverValue" @change="updateState"></my-input>
<my-input :initial="otherValue" @change="updateState"></my-input>
</card-body>
<card-footer>
<my-button :disabled="!serverValue || !otherValue"
@click="saveState"></my-button>
</card-footer>
</div>
</template>
<script>
import { mapGetters, mapActions } from 'vuex';
import { NS, ACTIONS, GETTERS } from '@/store/modules/api';
import { MyButton, MyInput } from './components';
export default {
components: {
MyInput,
MyButton,
},
computed: mapGetters(NS, [
GETTERS.serverValue,
GETTERS.otherValue,
]),
methods: mapActions(NS, [
ACTIONS.updateState,
ACTIONS.updateState,
])
}
</script>
Vuex 스토어 작업 은 백엔드 통신을 처리 하므로 여기의 컨테이너 는 axios 및 백엔드에 대해 알 필요가 없습니다.
$emit
v-model
에뮬레이트하기 위해 와 결합됩니다.sync
. 난 당신이 Vuex의 길을 가야한다고 생각합니다