컴포넌트 디자인 패턴

Jung taeWoong·2021년 4월 4일
1

vue.js

목록 보기
7/9
post-thumbnail

컴포넌트 디자인 패턴

  1. Common - 기본적인 컴포넌트 등록과 컴포넌트 통신
  2. Slot - 마크업 확장이 가능한 컴포넌트
  3. Controlled - 결합력이 높은 컴포넌트
  4. Renderless - 데이터 처리 컴포넌트

Common

기본적인 컴포넌트 설계 방식
container component presentational component

container component

  • 어떻게 동작하는지와 관련됨
  • 직접 만드는 것 보단 대게 Hight-Order Components를 이용해서 만들어진다.
// container component
<template>
  <div>
    <ChildComponent :items="items" @new="newItems"/>
  </div>
</template>

<script>
import ChildComponent from '경로';

export default {
  components: {
    ChildComponent,
  },
  data() {
    return {
      items: [1, 2, 3],
    }
  },
  methods: {
    newItems() {
      this.items = [10, 20, 30];
    }
  }
}
</script>

presentational component

  • 어떻게 보여지는지와 관련됨
  • 데이터를 가져오거나 변경하는 방법에 대해서 관여할 필요 없음
  • 상태를 거의 가지고 있지 않다. (상태를 가지고 있다면, 데이터에 관한것이 아닌 UI 상태에 관련된 것)
// presentational component
<template>
  <div>
  	<ul>
  	  <li v-for="item in items" :key="item.id">
        {{ item.name }}
   	  </li>
  	</ul>
	<button @click="$emit('new')"> new items </button>
  </div>
</template>

<script>
  export default {
	props: { // props validation 문법
  		items: {
          type: Array, // 타입 정의
          required: true, // 필수 값 속성 
        },
    }
  }
</script>

Slot

Slot을 이용하여 등록할때 컴포넌트를 확장하는 컴포넌트 디자인 설계 방식

// 부모 컴포넌트
<template>
  <child-component>
  	<!-- slot에 나타낼 영역을 정의-->
  	<!-- 부모 컴포넌트에서 스타일 지정 가능 -->
  	<div slot="test1" style="font-size: 20px;">test1</div>
	<!-- slot 속성으로 name 값과 매칭되는 슬롯에 연결 -->
	<div slot="test2">test2</div>
  </child-component>
</template>

// 자식 컴포넌트
<template>
  <li>
  	<slot name="test1"> 
  		<!-- 등록하는 곳에서 정의할 화면 영역 -->
  	</slot>
	<div>
      <slot name="test2"> <!-- name 속성으로 연결 가능 -->
      </slot>
    </div>
  </li>
</template>

Controlled

하위 컴포넌트와 상위 컴포넌트 데이터가 밀착된 형태로 설계된 컴포넌트
하위에서 관리하고 있던 데이터를 상위에서 관리하게 만드는 방법
컴포넌트에 데이터 의존성 분리하는 것들이 디자인 패턴의 핵심

// 부모 컴포넌트
<template>
  <!-- props로 값을 전달시 자식 컴포넌트에서 변경 불가 -->
  <!-- v-model은 @input 이벤트와 :value 값으로 조작이 된다. -->
  <CheckBox v-model="checked"/>
</template>

<script>
import CheckBox from '경로';

export default {
  comonents: {
    CheckBox,
  },
  data() {
    return {
      cehcekd: false,
    }
  }
}
</script>
// 자식 컴포넌트
<template>
  <!-- 받을 때는 :value라는 props로 받고 올릴떄는 @input으로 올림 -->
  <input type="checkbox" :value="value" @check="toggleCheckBox">
</template>

<script>
export default {
 // @input 이벤트
 // :value 값
 props: ['value'],
 methods: {
   toggleCheckBox() {
     this.$emit('input',!this.value);
   	}
   }
}
</script>

Renderless

templete 표현식이 없고 script단에서 비즈니스 로직만 처리해서 상위 컴포넌트로로 데이터를 노출시켜주는 컴포넌트
데이터 제공만 하는 컴포넌트

// 부모 컴포넌트
<template>
  <div>
  	<fetch-data url="https://jsonplaceholder.typicode.com/users/">
      <!-- ... --> slot-scope 안에서만 데이터 접근 가능
      <div v-slot:default="{ response, loading }"> 
        <div v-if="!loading">
        {{ response }}
        </div>    
        <div v-else>
          Loading...
        </div>
	  </div>
    </fetch-data>
  </div>
</template>

<script>
import FetchData from '경로';

export default {
  components: {
    FetchData
  }
}
</script>

// 자식 컴포넌트
<script>
import axios from 'axios';

export default {
  props: ['url'],
  data() {
    return {
      response: null,
      loading: false,
    }
  },
  created() {
    axios.get(this.url)
      .then(res => {
      this.response = response.data;
      this.loading = true;
    })
    .catch(err => {
      console.log(err);
    });
  },
  // render는 컴포넌트를 그리는 것
  render() {
    return this.$scopedSlots.default({
      reponse: this.response,
      loading: this.loading,
    });
  },
}
</script>

$scopedSlots

this.$scopedSlots.default()의 인자로 상위 컴포넌트에 범위가 있는 slot 데이터를 전달

render() 란?

template을 라이브러리 내부적으로 구현해주는 것

  • react는 render 함수로 구현을 하고 별도로 template 표현식을 작성하지 않음 (only JS)
render: function(createElement) {
  return createElement('태그 이름', '태그 속성', '하위 태그 내용');
}

// main.js
new Vue({
  // 1, 2, 3, 4 다 같은 방법
  render: h => h(App),
  // 1
  render: function(createElement) {
    return createElement(App);
  },
  // 2, h => hyperScript(virtual DOM)을 지칭하는 용어
  redner: function(h) {
    return h(App);
  },
  // 3
  render: h => {
    return h(App);
  },
  // 4
  render: h => h(App),
})
profile
Front-End 😲

0개의 댓글