[vuejs] Component 기초 - template, render, setup, slot

leteu

·

2023. 3. 4. 21:17

컴포넌트는 Vue에서 가장 기초가 되는 부분이다.

컴포넌트 하나 잘 만들어두면 비슷한 화면은 계속 가져다 쓸 수 있다.

Vue 3를 기준으로 작성하였다.


#1 참고

 

https://kr.vuejs.org/v2/guide/components.html

 

컴포넌트 — Vue.js

Vue.js - 프로그레시브 자바스크립트 프레임워크

kr.vuejs.org

 

일단 공식 문서를 보자. 답은 저기에 있다.

결론만 보고 싶다면 넘어가자

 

#2 화면

 

일단 제일 중요한 건 화면이다.

일단 뭐가 보여야 재밌으니 화면부터 들어가겠다.

Template, Setup, Render 이렇게 3곳 중 한 군대를 골라서 화면을 만들어줄 수 있다.

 

## template

 

  • 제일 익숙한 html로 짤 수 있다.
  • pug 언어로도 가능하다. ( 이 포스트에선 다루지 않는다 )

 

<template>
  <!-- 여기에 html 짜면 화면에 나온다 -->
  <div></div>
</template>

<script>
import { defineComponent } from 'vue'

export default defineComponent({
  setup() {
    
  },
})
</script>

 

## render

 

  • vue3에서 vue2와 문법이 바뀐 녀석이다.
  • h 함수를 vue에서 임포트 해와서 코드를 짤 수 있다.
  • 쓸 때 template은 지우고 써야 한다. 걔가 우선순위가 더 높다.

 

 

렌더 함수(Render Function) API | Vue.js

렌더 함수(Render Function) API 개요 이 변경사항은 사용자에게 영향을 주지 않습니다. 변경된 사항에 대한 간략한 요약은 다음과 같습니다: h는 이제 렌더 함수에 전달인자로 전달되는 대신에 전역 i

v3.ko.vuejs.org

 

h 함수는 React의 createElement와 매우 유사하다.

 

<script>
import { defineComponent, h } from 'vue'

export default defineComponent({
	setup() {
	},
	render() {
		return h(
			'div',
			{
				// 어트리뷰트
			},
			() => [
				// 하위 컴포넌트
			]
		)
	}
})
</script>

 

## setup

 

  • 여기서도 할 수는 있다. 근데 보통 여기서는 사용할 데이터를 선언해야 해서 잘 안 쓴다. 알아만 두자
  • template과 render는 지우고 사용하자
  • 웬만해선 여기선 하지 말자
  • 문법은 render와 같이 h 함수를 임포트 해와서 쓴다.

 

<script>
import { defineComponent, h } from 'vue'

export default defineComponent({
	setup() {
		return () => h(
			'div',
			{
				// 어트리뷰트
			},
			() => [
				// 하위 컴포넌트
			]
		)
	},
})
</script>

 

#3 컴포넌트 사용

 

컴포넌트를 만들어 놔도 불러오지 않으면 화면에 뿌릴 수 없다.

전체적으로 사용하는 컴포넌트는 전역으로 처리하고 아닐 경우에 아래 코드처럼 하나하나 import 해와서 사용해주면 된다.

 

// component.vue

<template>
  <!-- 여기에 html 짜면 화면에 나온다 -->
  <div></div>
</template>

<script>
import { defineComponent } from 'vue'

export default defineComponent({
  setup() {
    
  },
})
</script>

 

// index.vue

<template>
  <ComponenetVue />
</template>

<script>
import { defineComponent } from 'vue';
import ComponenetVue from './Component.vue';

export default defineComponent({
	component: {
		ComponenetVue
	},
  	setup() {
		
    },
})
</script>

 

이렇게 vue 파일을 import 하여 컴포넌트를 사용해줄 수 있다.

 

JSX로 짠 js/ts 컴포넌트 파일도 동일하게 불러와서 사용해 주면 된다.

 

# Slot

 

https://v3.ko.vuejs.org/guide/component-slots.html

 

Slots | Vue.js

Slots 이 페이지는 여러분이 이미 컴포넌트 기초를 읽었다고 가정하고 쓴 내용입니다. 컴포넌트가 처음이라면 기초 문서를 먼저 읽어주시기 바랍니다. Slot 컨텐츠 Vue는 Web Components spec draft (opens ne

v3.ko.vuejs.org

얘가 잘 쓰진 않지만 이해하고 있으면 활용하기 좋은 친구다.

 

// component.vue

<template>
	<div>
		<slot name="content">
	</div>
</template>

 

// index.vue

<template>
  <ComponentVue>
  	<template v-slot:content>
    	<!-- 여기에 적으면 컴포넌트 안에 적힌다 -->
    </template>
  </ComponentVue>
</template>

<script>
import { defineComponent } from 'vue';
import ComponentVue from './Component.vue';

export default defineComponent({
	component: {
		ComponentVue
	},
  	setup() {
		
    },
})
</script>

 

이렇게 컴포넌트 안에 원하는 위치에 따로 커스텀이 가능하다.

컴포넌트의 재사용을 늘릴 수 있다.

 

## h (createElement)

 

slot 또한 h 랜더 함수에서 사용할 수 있다.

h 함수를 import 한 위치를 따라가다 보면 확인할 수 있다.

(아래 코드는 IDE에서 h함수에 f12 연타해서 나온 코드들이다.)

 

export declare function h(type: string, children?: RawChildren): VNode;
export declare function h(type: string, props?: RawProps | null, children?: RawChildren | RawSlots): VNode;
export declare function h(type: typeof Text_2 | typeof Comment_2, children?: string | number | boolean): VNode;
export declare function h(type: typeof Text_2 | typeof Comment_2, props?: null, children?: string | number | boolean): VNode;
export declare function h(type: typeof Fragment, children?: VNodeArrayChildren): VNode;
export declare function h(type: typeof Fragment, props?: RawProps | null, children?: VNodeArrayChildren): VNode;
export declare function h(type: typeof Teleport, props: RawProps & TeleportProps, children: RawChildren): VNode;
export declare function h(type: typeof Suspense, children?: RawChildren): VNode;
export declare function h(type: typeof Suspense, props?: (RawProps & SuspenseProps) | null, children?: RawChildren | RawSlots): VNode;
export declare function h<P, E extends EmitsOptions = {}>(type: FunctionalComponent<P, E>, props?: (RawProps & P) | ({} extends P ? null : never), children?: RawChildren | RawSlots): VNode;
export declare function h(type: Component, children?: RawChildren): VNode;
export declare function h<P>(type: ConcreteComponent | string, children?: RawChildren): VNode;
export declare function h<P>(type: ConcreteComponent<P> | string, props?: (RawProps & P) | ({} extends P ? null : never), children?: RawChildren): VNode;
export declare function h(type: Component, props: null, children?: RawChildren | RawSlots): VNode;
export declare function h<P>(type: ComponentOptions<P>, props?: (RawProps & P) | ({} extends P ? null : never), children?: RawChildren | RawSlots): VNode;
export declare function h(type: Constructor, children?: RawChildren): VNode;
export declare function h<P>(type: Constructor<P>, props?: (RawProps & P) | ({} extends P ? null : never), children?: RawChildren | RawSlots): VNode;
export declare function h(type: DefineComponent, children?: RawChildren): VNode;
export declare function h<P>(type: DefineComponent<P>, props?: (RawProps & P) | ({} extends P ? null : never), children?: RawChildren | RawSlots): VNode;

 

children을 쓰는 곳에 그냥 h 함수나 h 함수의 배열을 쓰면 기본적으로 default 슬롯에 들어가게 된다.

따로 슬롯을 명시하여 사용하면 RawChildren 인터페이스가 아닌 RawSlots 인터페이스로 잡히게 된다.

 

h('예시 컴포넌트',
	{
    	// 어트리뷰트
    },
    {
    	default: () => [
        	h( ... ),
        ],
        
        '슬롯 name': () => [
        	h( ... ),
        	h( ... ),
        ]
    }
)

 

슬롯명: () => h( ... ) 형태로 사용하면 vue JSX에서도 슬롯이 사용 가능하다.

 


다음 포스트에선 prop, emit을 다뤄볼 예정이다.