개발을 하던 중 재사용
을 가능케하는 여러 요소들을 보며 어떤 점이 다르고 내가 아는 것 외에도 어떤 요소들이 있을지 궁금해져서 글을 쓰게 되었다!
재사용이란 공통으로 사용될 수 있는 로직을 한번만 구현하여 이곳 저곳에서 쓰이게끔 하는 것을 의미한다. 그렇다면 어떤 요소들이 있을까??
여러 컴포넌트 간에 공통으로 사용되고 있는 로직, 기능들 재사용하는 방법이다.
Mixin의 다양한 예시를 코드를 통해 살펴보자!
let mixin = {
created() {
console.log('mixin created!');
},
method: {
hello() {
console.log('mixin hello!');
}
}
}
let Component = Vue.extend({
mixin: [mixin]
});
let comp1 = new Component();
위와 같을 때 예상되는 결과는 ?? 바로 created 메서드가 실행되어 mixin created!
가 콘솔에 찍힌다. 이게 바로 Mixin 모든 옵션이 컴포넌트 고유 옵션에 혼합되는 예시
이다.
(그러면 comp1.hello() 를 하면 당연히 mixin hello!
가 콘솔에 찍히게 된다!!!)
let eunniverseMixin = {
data() {
return {
name: 'eunniverse',
gender: 'female'
},
created() {
console.log('eunniverse created!');
},
method: {
hello() {
console.log('eunniverse hello!');
}
}
}
let newEunniverse = new Vue({
mixin: [eunniverseMixin],
data() {
return {
name: 'notEunniverse',
age: 27
}
},
created() {
console.log(this.$data)
},
method: {
hello() {
console.log('new eunniverse hello!');
}
}
});
newEunniverse.hello();
위의 코드같은 경우, 선언한 data 중 name
, gender
이 같고, method 중 hello
가 중복된다. 그러면 어떻게 나올까??
결과는 바로 { name: 'notEunniverse', age: 27, gender: 'female'}
가 찍힌 후, new eunniverse hello!
가 콘솔에 찍힌다.
왜냐하면 중복되는 옵션
이 있을 경우 컴포넌트의 옵션이 우선순위
를 가지기 때문이다.
data
, methods
, created
, mounted
등 컴포넌트의 옵션이다. 자주 사용될만한 속성, 함수, 라이브러리를 설치하여 사용을 하는 속성(?) 혹은 기능(?)
// ===================== plugin 구현하기 =====================
// myPlugin.js
export default {
// install 메서드 구현 필요
install(Vue, options) {
Vue.myMethod = () => {
// 로직 생성....
}
}
//===================== plugin 사용하기 =====================
// ex) main.js
// myPlugin.install(Vue) 를 호출
Vue.use(myPlugin);
// Browserify 또는 Webpack을 통해 CommonJS를 사용할 때
var VueRouter = require('vue-router')
Vue.use(VueRouter)
위의 예시처럼 plugin 을 구현할 때는 install 메서드 노출
이 필요하다. 그리고 Vue.use(${plugin명})
으로 사용을 해주면 컴포넌트에서 매번 import를 해주지 않아도 사용할 수 있다.
컴포넌트 로직을 재사용하기 위한 React의 고급 기술로서 React의 컴포넌트적 성격에서 나타나는 패턴이다. 즉 컴포넌트가 컴포넌트를 새롭게 리턴해주는 것이다.
<!-- books.vue -->
<template>
<div>{{ data }}</div>
</template>
<script>
import axios from 'axios';
export default {
name: "books",
data() {
return {
data: null
}
},
// ======== 공통 로직 =========
created() {
axios.get("https://localhost:8080/books").then((res) => {
this.data = res.data;
});
},
</script>
<!-- myBooks.vue -->
<template>
<div>{{ data }}</div>
</template>
<script>
import axios from 'axios';
export default {
name: "myBooks",
data() {
return {
data: null,
}
},
// ======== 공통 로직 =========
created() {
axios.get("https://localhost:8080/books?id=1").then((res) => {
this.data = res.data;
});
},
};
</script>
위와 같이 공통 로직
이 있을 때, 사용할 수 있는데 HOC
이다. HOC로 사용하려면 다음의 절차가 필요하다!
with
으로 시작하는 함수를 만든다.with
이라는 접두어를 붙인다./* WithRequest.js */
import Vue from 'vue';
import axios from 'axios';
const WithRequest = (url) => (component) => {
return Vue.component("WithRequest", {
data() {
return {
data: null,
};
},
created() {
axios.get(url).then((res) => {
this.data = res.data;
});
},
render(createElement) {
return createElement(component, {
props: {
data: this.data,
},
});
},
});
};
export { WithRequest };
<!-- App.vue -->
<template>
<books />
<my-books />
</template>
<script>
import books from '@/components/books.vue';
import myBooks from '@/components/myBooks.vue';
import { WithRequest } from '@/WithRequest';
export default {
name: "App",
components: {
// books(기존 컴포넌트) : withRequest('url로 파라미터 넘기기')('새로운 컴포넌트')
// url을 파라미터로 넘기고 component를 받아 새로운 component를 리턴하는 구조
"books": WithRequest('https://localhost:8080/books')(books),
"my-books": WithRequest('https://localhost:8080/books?id=1')(myBooks),
},
};
</script>
<!-- books.vue -->
<template>
<div>{{ data }}</div>
</template>
<script>
import axios from 'axios';
export default {
name: "books",
props: {
data: Object
},
</script>
<!-- myBooks.vue -->
<template>
<div>{{ data }}</div>
</template>
<script>
import axios from 'axios';
export default {
name: "myBooks",
props: {
data: Object
}
};
</script>
import Vue from 'vue'
export function withComponent(components) {
return Vue.extend({
name: 'withComponent',
// vue 에서 jsx 컴포넌트를 렌터링하는 방법이 `render` 옵션 API이다!
render(h) {
return h(components, {
attrs: this.$attrs || {}, // attrs 전달
props: this.$props || {}, // props 전달
on: this.$listeners // 이벤트 전달
scopedSlots: this.$scopedSlots // slot 전달
})
}
})
}
참고)) 하위 컴포넌트에 slot 또한 전달할 수 있다!!
Mixin은 서로 다른 컴포넌트에 공통적인 기능을 제공할 수 있다는 장점이 있다. 하지만 Mixin이 복잡해지면 컴포넌트와 Mixin은 병합되기 때문에 컴포넌트의 복잡도 또한 올라간다. 이런 점과 비교하면 HOC는 컴포넌트 관계를 유지하며 컴포넌트를 한번 감싸는 형태로 사용되므로 기존 컴포넌트에 주는 영향도가 적다. 그리고 HOC 활용한 컴포넌트는 일반적인 컴포넌트이므로 props 활용, 옵션 비활성화 등의 유연한 처리가 가능하다.
한마디로 Mixin은 컴포넌트와의 병합, HOC는 컴포넌트의 관계 유지
가 차이점이다!!
옵션을 선언하는 대신 import한 함수를 사용하여 Vue 컴포넌트를 작성할 수 있는 API 세트이다.
import { reactive } from 'vue'
const algorithm: Book = {
code: 'AAAAAA',
createDate: '2024-05-27',
// ... 더많은 속성들
}
// 공통되는 함수를 hook 형태로 작성
export function borrowBook() {
const book = reactive(algorithm)
// 로직....
return { book }
}
<template>
<div>{{ book.name }}</div>
</template>
<script lang="ts">
import { borrowBook } from '../hooks/books'
export default {
setup() {
// hook 가져와서 사용하기
const book = borrowBook()
return book
}
}
</script>