Vue Components - #Part_2

YEZI🎐·2022년 11월 30일
0

Vue

목록 보기
21/45

재사용 가능한 컴포넌트 제작하기

컴포넌트를 작성할 때 나중에 다른 곳에서 다시 사용할 것인지에 대한 여부를 정해놓는 것이 좋다.
일회용 컴포넌트는 단단히 결합되어도 상관없지만,
재사용 가능한 컴포넌트는 깨끗한 공용 인터페이스를 정의해야 하며 사용된 콘텍스트에 대한 가정을 하지 않아야 한다.

Vue 컴포넌트의 API는 prop, event, slot으로 나뉜다.

  • Props : 외부 환경이 데이터를 컴포넌트로 전달하도록 허용
  • Event : 컴포넌트가 외부 환경에서 사이드 이펙트를 발생할 수 있게 함
    사이트 이펙트 - 부모∙자식 관계일 경우 : $emit
    ㅤㅤㅤㅤㅤㅤ ㅤ 부모∙자식 관계가 아닐 경우 : event bus
  • Slot : 외부 환경에서 추가 콘텐츠가 포함된 컴포넌트를 작성함
<my-component
  :foo="baz"
  :bar="qux"
  @event-a="doThis"
  @event-b="doThat"
>
  <img slot="icon" src="...">
  <p slot="main-text">Hello!</p>
</my-component>

자식 컴포넌트 참조

props나 이벤트가 있었음에도 불구하고 때때로 JavaScript로 하위 컴포넌트에 직접 액세스 해야 할 수 도 있다.
이를 위해 ref를 이용하여 참조 컴포넌트 ID를 자식 컴포넌트에 할당해야 한다.

<div id="parent">
  <user-profile ref="profile"></user-profile>
</div>

<script>
  var parent = new Vue({ el: '#parent' })
  // 자식 컴포넌트 인스턴스에 접근
  var child = parent.$refs.profile
</script>

ref가 v-for와 함께 사용될 때, 얻을 수 있는 ref는 데이터 소스를 미러링 하는 자식 컴포넌트를 포함하는 배열이 될 것이다.

비동기 컴포넌트

대규모 응용 프로그램에서는 응용 프로그램을 더 작은 덩어리로 나누고 실제로 필요할 때만 서버에서 컴포넌트를 로드해야 할 때가 있다.
Vue를 사용하면 비동기식으로 해결하는 팩토리 함수로 컴포넌트를 정의할 수 있다.
Vue는 컴포넌트가 실제로 렌더링 되어야 할 때만 팩토리 기능을 트리거하고 이후의 리렌더링을 위해 결과를 캐시 한다.

new Vue({
  // ...
  components: {
    'my-component': () => import('./my-async-component')
  }
})

팩토리 함수는 resolve 콜백을 받는다.
이 콜백은 서버에서 컴포넌트 정의를 가져왔을 때 호출되어야 하며, reject(reason)을 호출하여 로드가 실패했음을 알릴 수 있다.

Vue.component('async-example', function (resolve, reject) {
  setTimeout(function () {
    // 컴포넌트 정의를 resolve 콜백에 전달
    resolve({
      template: '<div>I am async!</div>'
    })
  }, 1000)
})

고급 비동기 컴포넌트

비동기 컴포넌트 팩토리는 다음 형태의 객체를 반환할 수 있다.

const AsyncComp = () => ({
  // 로드하는 컴포넌트(반드시 Promise이어야 함)
  component: import('./MyComp.vue'),
  
  // 비동기 컴포넌트가 로드되는 동안 사용할 컴포넌트
  loading: LoadingComp,
  
  // 실패했을 경우 사용하는 컴포넌트
  error: ErrorComp,
  
  // 로딩 컴포넌트를 보여주기전 지연하는 정도(기본값: 200ms)
  delay: 200,
  
  // 시간이 초과되면 에러용 컴포넌트 표시(기본값: Infinity)
  timeout: 3000
})

컴포넌트 이름 규약

컴포넌트 (또는 prop)를 등록할 때 kebab-case, camelCase, PascalCase를 사용할 수 있다.

// 컴포넌트 정의에서
components: {
  // kebab-case를 사용한 등록
  'kebab-cased-component': { /* ... */ },
  // camelCase를 사용한 등록
  'camelCasedComponent': { /* ... */ },
  // PascalCase를 사용한 등록
  'PascalCasedComponent': { /* ... */ }
}
<!-- HTML 템플릿에서는 항상 kebab-case를 사용 -->
<kebab-cased-component></kebab-cased-component>
<camel-cased-component></camel-cased-component>
<pascal-cased-component></pascal-cased-component>

예시

components: {
  'kebab-cased-component': { /* ... */ },
  camelCasedComponent: { /* ... */ },
  PascalCasedComponent: { /* ... */ }
}
  • kebab-case
    <kebab-cased-component></kebab-cased-component>
  • camelCase를 사용하여 컴포넌트가 정의된 경우 camelCase 또는 kebab-case
    <camel-cased-component></camel-cased-component>
    <camelCasedComponent></camelCasedComponent>
  • PascalCase를 사용하여 컴포넌트가 정의된 경우 kebab-case, camelCase, PascalCase
    <pascal-cased-component></pascal-cased-component>
    <pascalCasedComponent></pascalCasedComponent>
    <PascalCasedComponent></PascalCasedComponent>

Inline Templates

하위 컴포넌트에 inline-template이라는 특수한 속성이 존재할 때,
컴포넌트는 그 내용을 분산된 내용으로 취급하지 않고 템플릿으로 사용한다.
따라서 보다 유연한 템플릿 작성이 가능하다.

<my-component inline-template>
  <div>
    <p>이것은 컴포넌트의 자체 템플릿으로 컴파일됩니다.</p>
    <p>부모가 만들어낸 내용이 아닙니다.</p>
  </div>
</my-component>

그러나, inline-template 은 템플릿의 범위를 추론하기 더 어렵게 만든다.
가장 좋은 방법은 template 옵션을 사용하거나,
.vue 파일의 template 엘리먼트를 사용하여 컴포넌트 내부에 템플릿을 정의하는 것이다.

X-Templates

템플리트를 정의하는 또 다른 방법은 text/x-template 유형의 스크립트 엘리먼트 내부에 ID로 템플릿을 참조하는 것이다.

<script type="text/x-template" id="hello-world-template">
  <p>Hello hello hello</p>
</script>
Vue.component('hello-world', {
  template: '#hello-world-template'
})

이 기능은 큰 템플릿이나 매우 작은 응용 프로그램의 데모에는 유용할 수 있지만
템플릿을 나머지 컴포넌트 정의와 분리하기 때문에 피해야 한다.

Controlling Updates

Vue의 반응형 시스템은 업데이트 될 타이밍을 항상 알 수 있다.
하지만 반응형 데이터가 변경되지 않았음에도 예외적으로 컴포넌트를 강제 업데이트 해야하는 경우가 있다.
반대로, 불필요한 업데이트를 방지해야 하는 경우도 있다.

배열이나 객체를 이용한 반응형 시스템에서 변경 감지 주의사항을 설정하지 않았거나,
data와 같은 뷰의 반응형 시스템이 추적하지 못하는 상태에 의존하고 있는 경우가 있다.

극히 드문 경우로, 위의 경우 해당하지 않지만 UI에 데이터를 강제로 업데이트 해야하는 경우 $forceUpdate를 사용한다.

v-once를 이용한 정적 컴포넌트

일반 HTML 엘리먼트를 렌더링 하는 것은 Vue에서 매우 빠르지만 가끔 정적 콘텐츠가 많이 포함된 컴포넌트 가 있을 수 있다.
이런 경우, v-once 디렉티브를 루트 엘리먼트에 추가함으로써 캐시가 한 번만 실행되도록 할 수 있다.
하지만 이는 디버깅이 어렵고 추후에 이슈가 생길 수 있기 때문에 남용해선 안 된다.

Vue.component('terms-of-service', {
  template: '\
    <div v-once>\
      <h1>Terms of Service</h1>\
      ... a lot of static content ...\
    </div>\
  '
})


References

profile
까먹지마도토도토잠보🐘

0개의 댓글