Mixin
과 커스텀 컴포지션 함수
에 관하여 포스팅하는데사실 그동안 우리가 <bast-blabla> 이런식으로 만든 많은 컴포넌트들이 있다. 이것을 빌딩블록화하여 재사용해 온 것은 여전히 똑같다.
하지만 어떨 땐 로직의 일부가 남아서 재사용하고 싶어도 사용하지 못 하는 경험이 있다.
그래서 이러한 Options API
를 사용할 때 data(){}
, methods:{}
, computed:{}
, watch:{}
, life-cycle hooks
까지 컴포넌트 간 필요항 모든 구성요소를 공유할 수 있게 만들어주는 라이브러리가 바로 Mixin이다.
즉, 양 컴포넌트 간의 구성 공유를 쉽게 해주는 강력한 도구라고 생각하면 된다.
우선 src
폴더 바로 밑에 mixin
이라고 파일을 생성해준다. 마치 store 폴더를 따로 만들어 vuex의 state값들을 따로 관리해준것 처럼 말이다.
그리고 해당 폴더 밑에 .vue
가 아닌 .js
파일을 생성해준다.
이때 해당 파일에 중복되거나 반복하여 사용하고 싶은 로직을 덜어서 생성해준다.
import UserAlert from "@/components/UserAlert.vue";
export default {
components: {
UserAlert,
},
data() {
return {
alertIsVisible: false,
};
},
methods: {
showAlert() {
this.alertIsVisible = true;
},
hideAlert() {
this.alertIsVisible = false;
},
},
};
그리고 위 코드에서 보면 알 수 있듯 만약 import해올 파일이 있으면 반드시 사용되는 곳이 아닌 mixin 파일 자체에 넣어주어야한다.
결과적으로 이렇게 믹스인을 통해 거의 모든 컴포넌트 옵션을 공유할 수 있다.
울론 components 옵션이란 예외도 있다. 이는 아래서 다루겠다.
그 외에는 데이터, 연산 메서드, 감시자(Watcher) 등 필요한 모든 것을 믹스인을 통해 공유할 수 있다.
이렇듯 믹스인은 컴포넌트를 더 간결히 하고 컴포넌트 간에 재사용 로직을 공유하게 해주는 강력한 도구이다.
Mixin을 사용하려면 Vue.mixin 메소드를 사용하여 전역적으로 Mixin을 등록하거나, mixins 옵션을 사용하여 특정 컴포넌트에 Mixin을 적용할 수 있다.
우선 mixins 옵션에 대해 먼저 알아보자.
해당 로직을 사용하고싶다면 사용하고싶은 컴포넌트에 접근하여 export 한 .js
파일을 import 해준다.
mixins
라는 옵션값을 선언한다. 이때 type은 props와 같은 ary 타입이다.혹시 위와같은 에러가 뜬다면 component를 resolve하지 못 했기 때문에 해당 mixin 파일에 components 프로퍼티를 삭제하고 따로 컴포넌트단에서 작성해줘야한다.
컴포넌트에 등록해야 할 components가 있을 시 components 옵션은 믹스인을 통해 공유할 수 없다고 한다.
(그런데 난 왜 되지...?) => 하지만 로직을 공유하는 기능이고 또 OptionsAPI의 data, methods, computed, watch, life-cycle을 재사용하기 위해 만들어진 기능이니 components 프로퍼티는 사용되는 컴포넌트에 작성해주도록 하자.
Mixin은 다른 컴포넌트의 Option API과 병합되어 최종 컴포넌트 Option API을 형성하는데 이때 동일한 Option API 이름이 충돌할 경우, 컴포넌트의 Option API이 우선순위를 가지게 된다.
이는 매우 안 좋은 상황이다. 왜냐하면 오용되면 컴포넌트 간의 의존성을 알기 어렵게 만들 수 있기 때문이다.
Mixin을 적용한 컴포넌트의 동작을 이해하기 위해서는 해당 컴포넌트와 적용된 모든 Mixin을 살펴야 할 수도 있다.
이는 코드의 추적과 유지보수를 어렵게 만들 수 있기 때문이다.
같은 이름의 데이터, 메서드 또는 라이프사이클 훅을 Mixin과 컴포넌트에서 동시에 정의하는 경우 예기치 않은 동작이 발생할 수 있다.
이러한 충돌을 피하기 위해 Mixin과 컴포넌트에서 고유한 이름을 사용하거나, Mixin을 사용하기 전에 충돌 가능성을 검토해야 한다.
Mixin은 재사용성과 코드 공유를 위해 사용되지만, 지나치게 많이 사용하면 코드를 이해하고 유지보수하기 어려워질 수 있다.
필요한 로직을 적절하게 분리하여 Mixin을 만들고, 컴포넌트 간의 관계와 의존성을 신중하게 설계해야 한다.
<template>
<user-alert v-if="alertIsVisible" :title=alertTitle @close="hideAlert">
<p>Do you want to continue with deleting a user?</p>
</user-alert>
<section>
<h2>Delete a User</h2>
<button @click="showAlert">Delete User</button>
</section>
</template>
<script>
import alertMixin from '../mixins/alert';
export default {
mixins:[alertMixin],
data() {
return{
alertTitle : 'Delete User?'
}
},
};
</script>
그래서 따로 해당 컴포넌트에 hideAlert
메서드나, alertIsVisible
데이터 옵션을 설정하지 않아도 적용이 된다.
그렇다면 같은 것을 설정한다면 어떻게 될까? 앞서 주의사항에서 언급한 것 처럼 mixin option
보다 components option
이 더 우선이다.
즉, components option
이 mixin option
을 overide
한다.
앞서 언급한 mixin은 지역적인 mixin으로 <style scoped> 처럼 지역적으로 해당 컴포넌트에만 적용하는 방식이다.
그렇다면 이제 전역적으로 사용하는 방법에 대하여 알아보자.
하지만 이러한 전역 mixin은 용도가 아주 제한적이기에 모든 컴포넌트에 추가하려는 일부 로깅 또는 분석 기능
정도가 사용에 적합하겠다.
즉, 컴포넌트가 언제 마운트되었는지를 알려준다든가 그런 것들을 뜻한다.
export default {
mounted() {
console.log('mounted!');
},
}
위 객체에서 데이터를 변경할 건 아니고 대신 마운트된 생명 주기 훅을 추가해준다.
이때 모든 컴포넌트에 추가된다고 생각해도 된다.
참고로 이 믹스인이 마운트된 생명 주기 훅을 이미 갖고 있는 컴포넌트와 병합된다면 컴포넌트와 믹스인이 각각 가지는 두 생명 주기 훅이 모두 실행된다. overide되지 않는다는 뜻이다.
컴포넌트에 있는 생명 주기 훅이 가장 늦게 실행되고 따라서 믹스인에서 발생한 변경 사항을 덮어쓸 수 있다.
여기 있는 어떤 데이터베이스에 어떤 분석 데이터를 저장한다거나 뭐 이런 일들도 전역 믹스인에서 수행될 수 있다.
이제 전역에 "등록"을 해보자.
import { createApp } from 'vue';
import App from './App.vue';
import loggerMixin from './mixins/logger'
const app = createApp(App)
app.mixin(loggerMixin);
app.mount('#app');
app.comp() 가 글로벌 컴포넌트로 선언했던 것 처럼 app.mixin()을 사용하면 된다.
전역 mixin은 정말 쓸데가 거의 없으나 애플리케이션의 전체 컴포넌트에 어떤 기능을 추가하는 경우에는 필요할 수 있으니 알아 두면 좋을 수도 있다.
큰 애플리케이션을 구축하거나 여럿이서 팀으로 작업하는 경우 mixin인은 코드와 컴포넌트 구성 이해를 방해하는 요인이 될 수 있다.
왜냐하면 어떤 값이 어디서 오는지가 항상 명확하진 않기 때문이다.
사진으로 보면 좀 더 이해가 쉬운데 위 마크업단에 보면 굉장히 많은 변수와 메서들이 생략되어있음(mixin안에 포함)에도 IDE가 인식하고 오류를 내보내지 않고 있다. 따라서 만약에 이러한 mixin이 5~6개 까지 늘어난다면 뭐가 어디서 오는지 알 수 없다.
즉, hideAlert이라는 함수를 바꿀 때 mixin이 개많으면 이 mixin을 다 찾으러 다녀야한다는 것이다.
기본 병합 전략이 여러분에게 적합하지 않은 경우를 가정해보자. 물론 overide도 가능하지만 mixin이 똑바로 작동하게 하려면 그만큼 신경을 더 많이 써야한다.
그렇게 한다고 해도 여전히 이 메서드는 어디에서 오고 저 데이터 조각은 또 어디에서 오는 건지 바로 알아차리기 어렵다는 문제가 남아 있게되는 것이다.