HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
📝
학습 TIL
/
📝
42일 차 배운 것 정리
📝

42일 차 배운 것 정리

목차

목차1. Vue 5화 (Day38) - 컴포넌트1. 컴포넌트 등록1-1. 컴포넌트 이름1-2. 전역/지역 등록2. 컴포넌트 props. (29m)2.1. 정적/동적 props 전달2-2. 단방향 데이터 흐름2-3 prop의 유효성검사2-4. 컴포넌트 non-prop (16m) - 다시듣기3. 컴포넌트 커스텀 이벤트 (26m)3.1 커스텀 이벤트 정의하기3.2 v-model 인자4. 컴포넌트 Slots (18m, 2배속 필기 최소화)5. 동적 컴포넌트 (10m, 2배속 필기 최소화)6. Refs (21m, 2배속 필기 최소화)

1. Vue 5화 (Day38) - 컴포넌트

1. 컴포넌트 등록

💡
컴포넌트 이름, 전역/지역 등록, 모듈시스템

1-1. 컴포넌트 이름

  • 영문 소문자만 사용
  • 하이픈 사용
  • 이름 대소문자 규칙
    • SFC(SingleFileComponent)내에서는 파스칼 케이스(MyComponentName)으로 지정
 

1-2. 전역/지역 등록

tip 일반적으로는 지역등록을 권장하고, button과 같이 자주 사용되는 컴포넌트만 전역으로 등록
  • 전역등록
    • at main.js
      • app.component(’컴포넌트이름’, import한 컴포넌트) 로 등록
      • 원하는 vue 파일의 template에서 ‘컴포넌트이름’ 으로 import 없이 바로 사용
  • 지역등록
    • at 원하는 사용 컴포넌트 파일.vue
      • import 컴포넌트 후 , components:{Hello: Hello} 의 객체로 등록

2. 컴포넌트 props. (29m)

💡
props전달, prop유효성검사

2.1. 정적/동적 props 전달

props란, 컴포넌트 밖의 data를 컴포넌트 안으로 넣어주는 것 v-bind(:)를 통해 동적인 data도 전달 가능
  • 정적 전달
    • <blog-post title="Vue와 떠나는 여행"></blog-post>
  • 동적 전달
    • <blog-post :title="post.title + ' by ' + post.author.name"></blog-post>
 
  • 객체의 속성 전달
    • 객체의 경우 각 속성을 모두 작성하는 것이 아니라, v-bind=’객체명’ 을 통해 객체의 모든 속성을 한 번에 넣어줄 수 있다.
 

2-2. 단방향 데이터 흐름

  • props의 경우 부모에서 자식으로 흐르지만, 자식에서 부모로 올라갈 수 는 없다.
    • 즉 prop를 수정하려고 시도하면 안된다!
    • data 흐름을 파악하기 쉽도록 하는 규칙
    •  
  • prop을 변경하는 2가지 경우
    • 초기값을 prop으로 사용하는 경우
      • data속성으로 이 prop값을 지정하여, 해당 data를 수정하여 사용하기
      • initialProps 예시
    • prop이 변환해야하는 원시 값인 경우
      • computed 속성으로 props로 들어온 값을 변경한 값을 사용
      • size 코드 예시
         

2-3 prop의 유효성검사

  • 해당 컴포넌트에서 props 속성에서 props를 2가지 방법으로 받을 수 있다.
    • 배열 형식 : props: [id, tile, email, ...]
    • 객체형식: props : { id: Number, title:[String, Numnber], email:String }
      • 객체형식을 사용할 경우, key값으로 props명, value로 해당 prop의 type을 명시해야한다.
      • 여러개 Type이 가능한 경우 배열로 표기한다.
      • prop의 default 값을 지정하고 싶은 경우, 객체 리터럴 방식을 통해 ‘default’ 라는 속성의 값으로 정의한다.
        • required 속성을 통해 필수 값을 지정할 수 있다.
        • code 예시
  • 주의 기본적으로 null, undefined는 모든 유효성 검사를 통과한다.
  • 커스텀 유효성 검사 함수 추가 가능
    • custom 유효성 검사 code

2-4. 컴포넌트 non-prop (16m) - 다시듣기

  • 최상위 요소가 여러 개일 경우 inline 스타일이 적용되지 않는 경우
    • 상위요소의 속성정보($attrs)를 가져와 등록하는 것으로 해결할 수 있다.
      • :class = $attrs.class , :style=$attrs.style, @click=”$attres.onClick”
      코드 예시
      notion image

3. 컴포넌트 커스텀 이벤트 (26m)

💡
emit , event 유효성검사

3.1 커스텀 이벤트 정의하기

  • 1. 자식요소의 event핸들러를 $emit(’customEventName’)으로 지정
    • <div @click=”$emit(’customEventName’)”>
  • 2. 부모요소에서 자식요소에서 지정한 customEventName을 캐치하여 특정 동작하도록 등록
    • <div @please=”reverseMsg”>
    • methods 속성에 reverseMsg 정의하기
 
  • Tip 자식요소에서 emit을 등록한 customEventName을 emits 속성의 배열 형태로 명시해주어서, 해당 컴포넌트에서 어떤 customEvent들을 가지고 있는 지 관리할 수 있다. (필수는 아니지만 권장됨!)
    • emits : [”customEventName1”, ”customEventName2”, ...]
    • 객체 형식으로 선언함으로써 Emit된 event들을 명시할 뿐만 아니라, 유효성검사를 진행할 수 있다.
      • 유효성 검사 진행하지 않으면 null 입력, 유효성검사 인자에 따라 true/false를 반환하도록 구성
        • 주의 단 false를 리턴하여도, 이벤트함수 자체는 실행됨
        • email, password 유효성검사 예제

3.2 v-model 인자

💡
props로 받은 data를 v-model에서 사용하면, 양방향 바인딩을 하게 되므로 props의 변경을 유발하여 사용불가하다. 이때 에는 —
  • input 변경 예제
    • 부모요소에서 v-bind(:)로 data props로 내려준다. (:message =”msg”)
    • 자식요소에서 props로 message를 등록하고, input의 value 값으로 message를 지정한다
      • props:[’message’] & <input :value=”message” />
    • 자식요소에서 ‘update’ 라는 커스텀이벤트를 만들고 input변경 메서드에 $emit으로 등록한다. 이때 현재 input의 값을 두번째 인자로 같이 보낸다.
      • <input @input =”$emit(’update’, $event.target.value)” />
      input 변경 전체 코드
      • App.vue
      • HelloItem.vue
컴포넌트 단위에서 v-model을 통해 단순화 하기
  • 양방향 바인딩을 하고 있는 data임을 modelValue를 통해 알려서 v-model 사용가능
    • 주의 꼭 value의 이름이 ‘modelValue’ 가 아니여도 됨
      • 부모에서 v-model:customName 으로 지정해줄 수 있음 (해당 이름을 input :value=”customName” 및 emit의 update:customName부분에 같은 이름으로 사용하면 됨)
  • before (부모)
    • <Hello :message="msg" @update="msg = $event" />
  • before (자식)
    • <input :value="message" @input="$emit('update', $event.target.value)" />
  • after (부모)
    • <Hello v-model=”msg” />
  • after
    • html
      • <input :value="modelValue" @input="$emit('update:modelValue', $event.target.value)" />
    • props
      • props: {modelValue :{type, default}}

4. 컴포넌트 Slots (18m, 2배속 필기 최소화)

  • slot은 컴포넌트의 태그들 사이에 해당하는 값을 출력하고 있는 태그를 말함
  • 부모컴포넌트: <Component>{value}</Component> ⇒ 자식 컴포넌트: <slot>{value} </slot>
    •  
  • 기본 사용 예제 코드
    • 코드 보기
      • 부모 컴포넌트
      • 자식 컴포넌트 (Hello)
  • fallback Content
    • 컴포넌트 사이의 값이 없을 때 기본값으로 출력되는 value를 의미
    • <slot> fallbackContent 작성 </slot>
  • 컴포넌트 사이의 여러개의 태그가 존재하는 경우 template으로 범위와 name을 지정하여, 서로 다른 위치에 자리하도록 할 수 있다.
    • v-slot:abc v-slot:xyz
      • v-slot의 약어로 ‘#’ 기호 사용 가능 #abc, #xyz
  • 범위를 갖는 Slot 은 문서 참고하기!

5. 동적 컴포넌트 (10m, 2배속 필기 최소화)

<component :is="componentName" /> 디렉티브로 사용하며, 해당 data의 여부에 따라 컴포넌트의 렌더링 여부를 결정할 수 있음
  • 주로 navBar 에서 클릭을 통해 해당 페이지컴포넌트를 불러오는 등에 활용된다.
 
  • 클릭을 통해 현재 컴포넌트 바꿔서 렌더링 하는 예제
    • 코드 보기
       
 
  • keep-alive 태그를 통해, 캐싱하여 렌더링 최적화 하기
    • 동적으로 자주 변화가 있는 컴포넌트만 keep-alive 사용할 것 (메모리사용하므로)

6. Refs (21m, 2배속 필기 최소화)

자식 컴포넌트의 html 요소를 직접 접근할 때 사용
  • 문제 domAPI를 사용하면, 전체 트리 구조에서 검색을 진행해서 프로젝트가 커지면 부담이 갈 수 있다는 단점
  • 해결 현재 컴포넌트 내부에서만 검색범위를 좁히도록 함
    • <h1 ref=”hello”> ⇒ this.$refs.hello 로 탐색 가능
    • 주의 mounted() 시점 이전에는 렌더링이 되지 않으므로 사용할 수 없다.
 
  • 컴포넌트 단위에서 ref 적용하기
    • Vue app이 기본으로 가지는 $refs 속성을 통해 해당 컴포넌트에 접근하고, 해당 컴포넌트의 $el로 요소 접근한다.
      • <Hello ref=”hello” /> ⇒ this.$refs.hello.$el
      • 주의 최상위 요소가 여러개 일 때는 $el에 특정요소가 잡히지 않는다.
        • 해결 해당 컴포넌트 내부에서 필요한 요소의 ref를 걸어주고 접근
          • this.$refs.hello.$refs.world
    • input ref를 찾아 foucs 해보는 예제
      • 코드보기
notion image
대주제
Vue
작성완료
작성완료
전날 정리 노트 이동
다음 정리 노트 이동
주제
props 다루기
커스텀이벤트($emit)
slot
동적컴포넌트(:is)
Ref
날짜
May 17, 2022
props: ['initialCounter'], data() { return { counter: this.initialCounter } }
props: ['size'], computed: { normalizedSize: function () { return this.size.trim().toLowerCase() } }
export default { props: { id: { type:Number, required:true, }, title: String, email: { type: String, default: "outwater!!", }, }, }
propF: { validator: function(value){ return ['success', 'warning', 'danger'].indexOf(value) !== -1 } }
// html <button @submit="submitForm">제출</button> // js app.component('custom-form', { emits: { // 검사 절차 없음 click: null, // submit 이벤트 검사 submit: ({ email, password }) => { if (email && password) { return true } else { console.warn('잘못된 이벤트 페이로드입니다!') return false } } }, methods: { submitForm() { this.$emit('submit', { email, password }) } } })
<template> <h1>{{ msg }}</h1> <Hello :message="msg" @update="msg = $event" /> </template>
<template> <div> <label> <input :value="message" @input="$emit('update', $event.target.value)" /> </label> </div> </template> <script> export default { props: { message: { type: String, default: "", }, }, </script>
<template> <Hello> <template #abc> <h1>SlotContent ABC</h1> </template> <template #xyz> <h1>SlotContent XYZ</h1> </template> </Hello> </template>
<template> <slot name="abc" /> <h1>Title</h1> <slot name="xyz" /> </template>
<template> <button @click="currentComponent = 'Hello'">Hello</button> <button @click="currentComponent = 'World'">World</button> <component :is="currentComponent" /> </template>
// Html <div v-if="!isEdit"> {{ msg }} <button @click="onEdit">Edit</button> </div> <div v-else> <input ref="input" v-model="msg" type="text" @keyup.enter="isEdit = false" /> </div>
// js import { nextTick } from "@vue/runtime-core"; export default { data() { return { msg: "hello vue!", isEdit: false, }; }, methods: { onEdit() { this.isEdit = !this.isEdit; nextTick(() => { this.$refs.input.focus(); }); // setTimeout(() => { // this.$refs.input.focus(); // }); }, }, };