[DAY 37] Vue (5)
1. slot
: 부모 컴포넌트에서 자식 컴포넌트의 엘리먼트를 지정할때 사용
1) 기본 형식
- 부모 컴포넌트
<ChildComponent>
<h1>Hello Vue</h1>
</ChildComponent>
- 자식 컴포넌트
<template>
<div>
<!-- 부모에서 정의한 'Hello Vue'가 위치 -->
<slot></slot>
</div>
</template>
2) slot 이름 지정
v-slot 디렉티브를 이용하여 slot 요소가 여러 개일때 이름을 붙여 지정해 줄 수 있다. (축약 #)
<Hello>
<h2 v-slot:abc>ABC</h2>
<h2 #xyz>ABC</h2>
</Hello>
<template>
<slot name="abc"></slot>
<slot name="xyz"></slot>
</template>
3) slot의 props
- v-slot:default를 이용하여 하위 컴포넌트의 데이터를 가져와 출력할 수 있다.
- #['이름'] 형태로 동적으로 이름을 지정해 줄 수 있다.
<Hello>
<template #default="slotProps">
{{ slotProps.hello }}
</template>
<template #[slotName]="{ hello }"> // slotProps.hello
{{ hello }}
</template>
</Hello>
...
data(){
return {
slotName: 'xyz'
}
}
<template>
<slot :hello="123" name="xyz"></slot>
</template>
2. 동적 컴포넌트
: 화면에 보여질 컴포넌트를 동적으로 제어할 수 있다
<component :is="컴포넌트이름" />
- 컴포넌트가 전환될 때마다 페이지가 재랜더링 되는 것을 피하고 싶을 때,
keep-alive을 이용하여 렌더링 비용을 최소화 할 수 있다.
<template>
<button @click="currentComponent = 'Hello'">Hello!</button>
<button @click="currentComponent = 'World'">World!</button>
<div>{{ msg }}</div>
<keep-alive>
<component :is="currentComponent" />
</keep-alive>
</template>
위 경우에는 컴포넌트가 바뀌어도 Hello, World 컴포넌트가 재 랜더링 되지 않는다.
3. refs
: 컴포넌트나 Dom에 접근할 때 효율적으로 접근할 수 있게 하는 속성
1) 사용 방법
- 참조하려는 요소에 ref 속성 부여
<input ref="input">
- script 내에서 this.$refs로 접근 가능하다. (mounted 이상에서 사용 가능)
<script>
export default {
mounted() {
this.$refs.input.focus()
}
}
</script>
✅ 참조 하려는 요소가 컴포넌트 일 때
- 컴포넌트 내부 요소가 한 개라면, this.$refs.[ref이름].$el 로 접근할 수 있다.
- 내부 요소가 여러 개면, 내부 요소에 개별적으로 ref 속성을 부여해줘야 한다.
<!-- 하위 컴포넌트 -->
<template>
<h1 ref="world">World</h1>
</template>
<Hello ref="hello" />
상위 컴포넌트에서 this.$refs.hello.$refs.world 로 접근 할 수 있다.
📌주의사항
- refs로 참조한 요소는 렌더링을 바로 보장하지 않는다.
- 그 요소에 대한 메서드를 추가하고 싶으면, $nextTick 메서드를 이용해야 한다.
onEdit() {
this.isEdit = true;
// 렌더링을 바로 보장하진 않는다.
this.$nextTick(() => {
this.$refs.editor.focus();
}, 0);
},
위 경우 처럼 어떠한 input 요소에 focus를 하고 싶을 때, nextTick을 이용해야한다. (아니면 setTimeout)
4. 플러그인
: 자주 사용하는 커스텀 메서드에 대해 전역적으로 사용할 수 있게 해주는 도구
1) 사용 방법
export default {
install(app, options) {
app.config.globalProperties$함수이름 = (arg) => {
};
},
};
export default {
install(app, options) {
app.config.globalProperties[options.pluginName] = (arg) => {
};
},
};
- main.js에서 불러와 전역적으로 사용할 수 있다.
app.sue(불러온이름)
app.use(불러온이름, {
// pluginName: '$myName'
});
- 개별 컴포넌트에서는 this.$함수이름 으로 사용할 수있다.
5. 믹스인
: Vue 컴포넌트에 재사용 가능한 컴포넌트 옵션을 가져와 기존 옵션들과 혼합하여 사용할 수 있다.
1) 사용 방법
- mixin 객체를 정의한다. (따로 파일로 뺄 수 있음)
const myMixin = {
created() {
this.hello()
},
methods: {
hello () {
console.log('hello from mixin!')
}
}
}
- 사용할 컴포넌트에 불러온다.
export default {
mixins: [myMixin],
data() {
return {};
},
methods: {},
};
📌 같은 이름의 메서드는 덮어써지는게 아니라 mixin이 먼저, 컴포넌트의 메서드가 그 후 호출된다.
다른 것들은 컴포넌트가 mixin을 덮어쓴다.
6. Teleport
: 원하는 요소를 외부에 있는 Dom 노드로 텔레포트 할 수있는 기능
<Teleport to="body">
<div v-if="open" class="modal">
<p>Hello from the modal!</p>
<button @click="open = false">Close</button>
</div>
</Teleport>
- to로 원하는 요소의 선택자를 넣는다.
- 텔레포트를 여러개 하면 먼저 작성한 코드 먼저 텔레포트 된다..
7. Provide/inject
: 부모 컴포넌트가 하위 컴포넌트들에 데이터를 내려줄 때 한번에 데이터를 전달 할 수 있는 기능
1) 사용 방법
- 부모 컴포넌트에 provide 메서드 생성
provide() {
return {
msg: 'hello!',
};
},
- 부모의 하위 요소에서 inject 메서드로 데이터를 가져온다.
export default {
inject: ["msg"],
};
⚠️ inject로 가져온 데이터는 반응성을 가지지 않는다.
해결방법은 부모 요소에서 해당 데이터를 computed로 감싸주면 된다.
8. Vuex
: Vue의 데이터를 전역으로 관리할 수 있게 해주는 모듈
1) 설치 방법
npm i vuex
2) 기본 형태
import { createStore } from "vuex";
export default createStore({
state() {},
getters: {},
mutations: {},
actions: {},
modules: {},
});
- state : 상태의 집합
- getters : state를 변경시킬 때 사용(전달인자 x, computed에 등록)
- mutations: state 변경시킬 때 사용(전달인자 o, methods에 등록)
- actions : 비동기적 변이를 다루는 속
- modules: vuex의 상태를 모듈화 했을 때 불러온 모듈 작성
* 모듈화 된 파일은 namespaced: true 속성을 제일 앞에 적어둬야 된다.
3) 사용 방법
① state
state() {
return {
message: "Hello Store Vue?!",
};
},
return문 안에 객체 형태로 데이터를 선언한다.
전역적으로 불러온 store에 대해 컴포넌트에서 아래와 같이 데이터를 불러와 사용할 수 있다.
<template>
<h2>{{this.$store.state.message}}</h2>
</template>
* 지역적으로 store를 불러왔다면, state 이름만 작성해도 된다.
② getters
getters: {
reversedMessage(state) {
return state.message.split("").reverse().join("");
},
},
인자로 자신의 내부 state를 받아온다. state를 이용하여 값을 변경할 수 있다.
* 두번째 인수로 다른 getter를 받아올 수 있다.
컴포넌트에서 사용하는 방법은 아래와 같다. computed에 등록하여 사용한다.
export default {
computed: {
reversedMsg() {
return this.$store.getters.reversedMsg;
},
},
};
✅ mapGetters
- 여러 getter 요소들을 간편하게 불러올 수 있게 하는 메서드
export default {
computed: {
...mapGetters([
'게터이름1',
'게터이름2',
])
}
}
③ mutations
mutations: {
updateMsg(state, newMsg) {
state.msg = newMsg;
},
},
첫번째 인자로 state를 받아온다. 두번째 인자로 payload를 받아와 함수 내에서 활용할 수 있다.
컴포넌트에서 사용하는 방법은 아래와 같다. 첫번째 인자로 muatation 이름, 두번째 인자로 데이터를 넘긴다.
this.$store.commit('updateMsg', '새로운 메시지');
✅mapMutation
: 여러 mutations를 불러와 간편하게 쓸 수 있는 메서드
methods: {
...mapMutations(["뮤테이션이름1", "뮤테이션이름2"]),
...mapMutations("모듈이름", ["뮤테이션이름1", "뮤테이션이름2"]),
},
④ actions
actions: {
async fetchTodo(context) {
const todo = await fetch(
"https://jsonplaceholder.typicode.com/todos/1"
).then((res) => res.json());
context.commit("updateMessage", todo.title);
},
},
context는 { state, getters, commit, dispatch } 객체이다.
사용할 때는 methods안에 정의하고, dispatch라는 메서드를 이용한다.
this.$store.dispatch('fetchTodo');
✅ mapActions
: 마찬가지로 actions도 아래와 같이 불러올 수 있다.
methods: {
...mapActions(["액션이름1"]),
...mapActions("모듈이름", ["액션이름1"]),
},
⑤ 모듈 이용하기
개별 모듈은 namespace: true 속성을 제일 첫번째로 가진다.
전역으로 store를 선언하고, 개별 컴포넌트에서 사용할 때에는 아래 형태로 사용한다.
- state: this.$store.state.모듈이름.상태이름
- getters : this.$store.getters['모듈이름/게터이름']
- mutations : this.$store.commit('모듈이름/뮤테이션이름')
- actions : this.$store.dispatch('모듈이름/액션이름')