혼자 적어보는 노트

프로그래머스 데브코스 TIL - Day 38 본문

스터디

프로그래머스 데브코스 TIL - Day 38

jinist 2022. 5. 12. 18:12

 

✅ 오늘의 학습

📌 Vue (5)

 

- 컴포넌트 등록

- Props

- Non-Props

- 커스텀 이벤트

- Slots

- 동적 컴포넌트

- Refs

 


 

전역 컴포넌트

- main.js에서 생성한 app에 component 메서드를 통해 등록한 컴포넌트.

- 전역으로 컴포넌트를 등록하면 컴포넌트 어디에서든지 import를 하지 않고 등록한 컴포넌트를 사용할 수 있다.

import { createApp } from 'vue';
import App from '~/App';
import Btn from '~/components/Btn';


const app = createApp(App);

app.component('Btn', Btn);
app.mount('#app');

 

지역 컴포넌트

- 컴포넌트 내부에서 components 옵션을 통해 등록한 컴포넌트.

- 해당 컴포넌트 내부에서만 사용할 수 있다.

<template>
  <h1>Hello vue</h1>
  <Btn /> // 전역 컴포넌트
  <Hello /> // 지역 컴포넌트
</template>

<script>
import Hello from '~/components/Hello';

export default {
  components: {
    Hello
  }
};
</script>

 

 

 

컴포넌트 내부에서 props 데이터 수정하기

컴포넌트 내부에서는 props로 받은 데이터를 직접 수정할 수 없기 때문에

props로 받은 데이터를 컴포넌트 내부에서 데이터를 따로 담아서

해당 데이터를 변경하는 방식으로 사용할 수 있다.

<template>
  <h1 @click="updateMessage">
    {{ newMessage }}
  </h1>
</template>

<script>
export default{
  props: ['message'],
  data(){
    return {
      newMessage: this.message // props로 받은 데이터 할당
    };
  },
  methods:{
    updateMessage(){
      this.newMessage = 'New Message!';
    }
  }
};
</script>

 

 

props

 

공식 문서 : props

 

props로 전달할 데이터가 객체라면 객체 내부의 프로퍼티들을 한번에 전달할 수 있다.

<template>
  <Hello v-bind="post" />
</template>

 

참조형 데이터 타입 체크

객체나 배열의 default값은 항상 함수로부터 반환이 되어야한다.

  props:{
    id: Number,
    title: [String, Number],
    email:{
      type: String,
      default: '1111@abc.com'
    }
    data:{
      type: Object,
      // 객체나 배열의 기본 값은 함수로 반환
      default: function() {
        return { message: 'hello' }
      }
    },
  },

 

 

 

Props 대소문자 구분

HTML 속성명은 대소문자를 구분하지 않기 때문에

props를 통해 전달할 데이터 이름은 html상에서 케밥케이스로 작성을 하고

props를 받는 컴포넌트 내부에서는 카멜케이스를 사용해야 한다.

// HTML
<Post post-title="hello~" />

// Component Props
props: [postTitle]

 


non-prop 속성 ($attrs)

props나 emits에 정의 된 특성을 가지지 않은 속성 또는 이벤트리스너를 의미한다.
(ex: class, style, id, 이벤트 리스너)

 

 

상위 컴포넌트에서 하위 컴포넌트에 속성을 전달해 줄 때

하위 컴포넌트 내부에 최상위 요소가 하나일 경우 상속이 되고,

여러 개일 경우 $attrs를 사용하여 전달된 속성을 나누어 줄 수 있다.

 

❗❗ props로 명시를 한 속성들은 $attrs의 내장객체로 들어가지 않는다.

 

[App.vue]

<template>
  <h1>
    {{ msg }}
  </h1>
  <Hello
    class="hello"
    style="font-size:100px"
    @click="msg += '!!'" />
</template>

[Hello.vue]

<template>
  <h1 :class="$attrs.class">
    Hello
  </h1>
  <h2 :style="$attrs.style">
    Hello
  </h2>
  <h3 @click="$attrs.onClick">
    Hello
  </h3>
</template>

❗❗ 이벤트리스너를 전달받아서 사용할 때는 on키워드와 함께 사용해야 한다.

 

💡 모든 속성을 한 요소에 전달하기

<template>
  <h1 v-bind="$attrs">
    Hello
  </h1>
  <h2>Hello</h2>
  <h3>Hello</h3>
</template>

 

💡상속을 원하지 않는 경우엔 하위 컴포넌트에서 inheritAttrs옵션을 추가한다.

inheritAttrs: false,

 

 

하위 컴포넌트에 이벤트 리스너 전달

<Hello @click="msg += '!'" />

커스텀 이벤트가 아닌 네이티브 이벤트 리스너를 전달할 경우

emits옵션에 명시를 하면 내부 요소에 지정해서 이벤트 리스너를 추가할 수 있다.

<template>
  <div>
    <h1>A</h1>
    <h1 @click="$emit('click')">
      B
    </h1>
  </div>
</template>


<script>
export default {
  emits:['click'],
};
</script>

 

 

컴포넌트의 양방향 데이터 바인딩

[App.vue]

<template>
  <h1>
    {{ msg }}
  </h1>
  <Hello v-model:message="msg" />
</template>

v-model에 데이터명을 붙이지 않으면 modelValue로 전달이 된다.

 

[Hello.vue]

<template>
  <label>
    <input
      :value="message"
      @input="$emit('update:message', $event.target.value)" />
  </label>
</template>


<script>
export default {
  props:{
    message:{
      type: String,
      default: ''
    }
  },
  emits:['update:message'],
};
</script>

양방향 데이터 바인딩을 할 경우 $emit의 이벤트 이름은

update:[변경할 props이름]으로 지정해야 한다.

 

 

slot

공식문서 : Slot

컴포넌트 사이에 내용을 입력하면 내부의 컴포넌트의 slot태그 위치에 작성된다.
컴포넌트 사이에 내용이 없다면 slot태그 사이에 작성한 내용이 출력된다

 

컴포넌트의 내용을 분리해서 출력하고 싶다면 template에 name을 지정하여 아래와 같이 작성할 수 있다.

* #은 v-slot:의 약어

 

<template>
  <Hello>
    <template #star>
      <h2>★</h2>
    </template>
    <template #heart>
      <h2>♥</h2>
    </template>
  </Hello>
</template>
<template>
  <slot name="star">
    X
  </slot>
  <h2>---------</h2>
  <slot name="heart">
    X
  </slot>
</template>

 

범위를 가지는 Slot

슬롯에서 사용한 데이터를 슬롯을 사용한 범위에서 사용할 수 있다.

<template>
  <Hello>
    <template #default="slotProps">
      <h2>Hello {{ slotProps.num }}</h2>
    </template>
  </Hello>
</template>
<template>
  <slot :num="123"></slot>
</template>

 

 

동적 컴포넌트

<component :is="currentComponent" />

currentComponent의 값을 변경해가면서 컴포넌트의 노출을 변경할 수 있다.

 

keep-alive

토글 기능으로 currentComponent 의 값을 계속 바꿔주면 바꿀 때마다 컴포넌트가 생성되고 사라지는데

keep-alive로 래핑하면 한번 렌더링한 컴포넌트를 캐싱하여 다시 렌더링을 시키지 않는다.

* 캐싱을 하면 메모리를 소모하기 때문에 토글이 자주 일어나는 곳에서만 사용하는 것이 좋다.

  <keep-alive>
    <component :is="currentComponent" />
  </keep-alive>

 

 

Refs

ref 속성을 이용해 DOM에 직접 접근할 수있다.
* 해당 dom을 변경하려면 mounted 되었을 때 접근해야 한다.

<input ref="usernameInput" />
  methods: {
    focusInput() {
      this.$refs.input.focus()
    }
  },

 

 

$nextTick

공식문서: 인스턴스메서드

반응형 데이터는 변경되자마자 바로 적용이 되는 것 처럼 보이지만
vue내부의 최적화 과정으로 인해 완전 즉시 적용이 되는 것은 아니다.

setTimeout의 콜백함수를 통해 약간의 시간을 지연시킨 후에 적용시키는 방법도 있지만
vue의 내장 메서드인 $nextTick을 사용하면 같은 방식으로 구현할 수 있다.

 

 


 

✍ 느낀 점

 

지난 주 과제 때문에 강의가 조금 밀려있기도 했고 강의 내용이 많은 걸 다루다보니

이번 주는 거의 종일 강의만 들었다..

오늘은 거진 10시간을 강의듣고 정리만 하니깐 정신적으로 피곤한 느낌이다😱

그래도 이것 저것 공식문서에 있는것을 차례대로 짚어주며 하나씩 해보니

시간은 걸리지만 그래도 머릿속에 기억이 되는 것 같다.

물론 실제로 사용할 때도 딱딱 떠오를지는 아직 확신이 없지만..

잊어버리기 전에 빨리 과제를 진행해서 직접 부딪혀봐야겠다!

 

 

Comments