✅ 컴포넌트 슬롯
1. 슬롯이란
- 컴포넌트의 특정 영역을 대체하는 기술
- 리액트의 Children과 동일한 역할
- 부모가 템플릿 조각을 자식 컴포넌트에 전달
- 자식 컴포넌트가 전달받은 템플릿 조각을 렌더링할 수 있게 하는 기능
- 슬롯을 설정해두지 않으면 자식 컴포넌트로 감싸도 렌더링되지 않음
- 부모 컴포넌트에서 동일한 슬롯 이름으로 여러번 호출 시, 마지막 요소만 적용
2. 슬롯 사용 방식
이름이 없는 슬롯
<slot></slot>
- 자식 컴포넌트 사이에 들어가는 콘텐츠가
<slot></slot>
대신에 들어가게 됨
<Button>버튼</Button>
<slot></slot>
이름이 있는 슬롯
<slot name="값"></slot>
- 부모 컴포넌트에서
v-slot
으로 전달하는 값과 자식 컴포넌트의 name이 동일한 곳에 콘텐츠가 대신 들어감
- 단, 부모 컴포넌트에서의
v-slot
는 반드시 <template>
태그에 선언해야 함
- 일치하는 슬롯이 없으면 보여지지 않음
- 축약형 :
v-slot:값
⇒ #값
<template v-slot:값>
어쩌구 저쩌구
</template>
<slot name="값"></slot>
혼합 슬롯
- 이름이 없는 슬롯 + 이름이 있는 슬롯을 함께 사용하는 것
<slot></slot>
은 name="default"
가 자동으로 적용된 상태
v-slot
혹은 #
으로 넘어오는 값이 유효하지 않거나 없는 경우, default로 정의된 slot에 들어감
<slot name="name"></slot>
<slot></slot>
슬롯의 기본값
- 부모에서 콘텐츠 없이 자식 컴포넌트만 호출한 경우, 보여질 기본값
- 콘텐츠가 있다면 기본값은 적용되지 않음
<Child></Child>
<Child>안녕</Child>
<slot>기본값</slot>
동적 슬롯
- 슬롯의 이름을 동적으로 지정하는 것
- 동적으로 지정한다 === 슬롯의 이름을 변수로 지정해 넣는다
- 자식 컴포넌트의 slot 이름은 지정이 되어야함
v-slot="데이터"
아님 유의
<template v-slot:[dynamicName]></template>
<template #[dynamicName]></template>
슬롯 기본 범위
- 정리) 스타일, 데이터 모두 기본적으로 부모 컴포넌트의 영향을 받음
- 슬롯 자리에 들어가 렌더링 되는 요소는 각각 고유한 범위가 있음
- 슬롯의 스타일은 부모 컴포넌트의 영향을 받음
- 부모에서 사용된 요소들은 자식 컴포넌트 스타일이 적용되지 않음
- 슬롯의 데이터는 부모 컴포넌트의 영향을 받음
- 부모에는 없으면서 자식에는 있는 데이터를 사용하는 경우에도 전혀 적용되지 않음
- 슬롯의 범위를 지정하면 자식 컴포넌트의 데이터 사용 가능
슬롯 범위 지정
- 자식 컴포넌트의 범위에 접근할 수 있는 방법 제공
- 부모에 전달할 데이터를 슬롯에 v-bind로 미리 정의 (computed를 포함한 모든 데이터 가능)
- 부모는 전달된 데이터를 v-slot을 통해 객체 형식으로 받음
<slot :childData="childData"></slot>
<Child v-slot="myKey">{{ myKey.childData }}</Child>
<Child v-slot="{ childData }">{{ childData }}</Child>
<slot name="section" :childData="childData"></slot>
<Child #section="myKey">{{ myKey.childData }}</Child>
<Child #section="{ childData }">{{ childData }}</Child>
✅ 컴포지션 API
- Vue3에 추가된 문법 ⇒
setUp()
훅을 통해 사용 가능
- Vue3.2에 추가된 설탕 문법 ⇒
<script setup></script>
1. 반응형 데이터, ref와 reactive
ref
: 기본 자료형을 반응형 데이터로 정의할 때
reactive
: 참조 자료형을 반응형 데이터로 정의할 때
script 내부에서 반응형 데이터 접근
- ref로 정의된 데이터는 value를 통해서 접근
- reactive로 정의된 데이터는 일반 객체처럼 접근
<script setup>
import { computed, reactive, ref } from 'vue';
const count = ref(0);
const array = reactive([1, 2, 3]);
console.log(count.value, array[0]);
</script>
template 내부에서 반응형 데이터 접근
<template>
<div>{{ count }}</div>
<div>{{ array[0] }}</div>
</template>
2. 계산된 속성, computed
- 데이터 가공, 캐싱에 사용 (읽기 전용)
computed
함수 사용
- script 태그 내부에서 사용할 때, value를 통해서 접근
- template 태그 내부에서는 바로 사용
<script setup>
import { computed, ref } from 'vue';
const count = ref(0);
const doubleCount = computed(() => count.value * 2);
console.log(doubleCount.value)
</script>
<template>
<div>{{ doubleCount }}</div>
</template>
- computed 속성을 직접 변경하는 방법 ⇒ get과 set 함수로 세분화
<script setup>
import { computed, ref } from 'vue';
const firstName = ref("Minha");
const lastName = ref("An");
const fullName = computed({
get() {
return `${lastName.value} ${firstName.value}`
},
set(value) {
[lastName.value, firstName.value] = value.split(" ");
},
});
</script>
<template>
<div>{{ doubleCount }}</div>
</template>
3. 함수
- 함수 선언식, 함수 표현식, 화살표 함수 모두 사용 가능
- ref, reactive, computed 모두 접근 가능
<script setup>
import { ref } from 'vue';
const count = ref(0);
const increment = count.value++;
</script>
4. 감시자 속성 1 - watch
- 반응형으로 선언된 데이터의 값이 변경되었을 때, 이를 감시하여 코드를 실행시키는 속성
- 인자 목록
- 첫번째 인자 : 감시할 반응형 데이터
- 두번째 인자 : 콜백함수 (감시한 데이터가 변경될 때 실행 / 현재값, 이전값이 순서대로 인자로 들어옴)
- 세번째 인자 : (선택) 보통 deep 여부 선택.
- 참조 차료형을 감시하는 경우, 현재값과 이전값이 동일한 점 유의
ref 감시
- 변수 자체를 감시
- 기본 : 참조 자료형을 ref로 선언하는 경우, 변경 감지 불가
- { deep: true } 설정 : 참조 내부까지 변경 감지
reactive 감시
- 참조 자료형 감시
- 기본 : 참조 내부까지 변경 감지
옵션
deep(true)
: 참조 내부까지 감시 (ref)
immediate(true)
: 처음 디폴트 값을 넣을 때 부터 감시 및 실행 (기본값은 변경될 때만)
once(true)
: 최초 한 번만 실행
flush(선택값)
: 감시자가 실행되는 시점 설정
pre
: (기본값) 감시자가 DOM 업데이트 이전에 실행
post
: 감시자가 DOM 업데이트 후에 실행
sync
: 반응형 데이터가 변경되는 즉시 동기적으로 실행 (DOM에 반영 전)
5. 감시자 속성 2 - watchEEffect
- watch와 비슷한 역할
- watch와 다른 점
- deep 옵션 사용하지 않음
- immediate 옵션을 true로 고정 ⇒ 처음 디폴트 값을 넣을 때 부터 감시 및 실행
- 감시 대상을 따로 지정하지 않으나, 콜백 함수 내에서 사용하고 있는 반응형 데이터들을 자동 감시
watchEffect(() => {
console.log(count.value);
console.log(state.count);
console.log(state);
6. 감시자 속성 3 - watchPostEffect
- watchEffect와 flush를 ‘post’의 결합
- DOM이 갱신된 후 실행
7. 라이프사이클 훅
- Options API에서 사용하던 beforeCreate()와 create()는 setup 영역으로 대체
- 나머지 훅은
on + 기존 메서드명
으로 변경
8. props 전달
defineProps()
함수를 사용하여 props 받음
<script setup>
import { defineProps } from 'vue';
const props = defineProps({
count: Number
text: {
type: String,
default() { return '기본' }
})
</script>
<template>
<p>{{ props.count }}</p>
<p>{{ props.text }}</p>
</template>
9. 이벤트 받기
defineEmits()
함수를 사용하여 이벤트를 받음
<script setup>
import { defineEmits } from 'vue';
const emit = defineEmits(['event1', 'event2'])
const handler = () => {
emit('event1')
}
</script>
<template>
<button @click="handler">버튼1</button>
<button @click="emit('event1')">버튼2</button>
<button @click="emit('event2', 10, [20])">버튼3</button>
</template>
10. provide & inject
- props drilling을 방지할 수 있는 방법
- props를 사용하지 않고 데이터를 전달할 수 있는 방법
- provide를 사용한 컴포넌트부터 하위 컴포넌트들이 inject로 접근해서 사용 가능
- 형식
provide(고유한 식별자, 제공할 데이터)
⇒ 데이터는 일반, ref, reactive, coumputed 모두 가능
const value = inject(고유한 식별자, 기본값)
⇒ 기본값은 생략 가능
<script setup>
const count = ref(0);
const array = reactvie([1, 2, 3])
const increment = () => (count.value++)
provide('provideCount', count)
provide('provideArray', array)
</script>
<script setup>
const count = inject('provideCount', 0);
const array = inject('provideArray');
</script>
✅ 플러그인
unplugin-auto-import
- 모든 컴포넌트에서 메서드를 import 하지 않아도 사용 가능
import AutoImport from 'unplugin-auto-import/vite'
export default defineConfig({
plugins: [ ..., AutoImport({ imports: ['vue'] })],
...
📌 출처
수코딩(https://www.sucoding.kr)