Vue 스터디

Vue.js 에서 HOC(High Order Component) 만들기

옹재 2021. 7. 15. 16:53
728x90
반응형

HOC(High Order Component)란?

자주 반복해서 작성하게 되는 코드를 함수화하여 재사용하는 것을 말합니다. 리액트에서는 자주 반복되는 코드를 공통화한 뒤 props로 컴포넌트를 받아 로직을 처리한 후에 컴포넌트를 리턴해주는 형식으로 많이 사용됩니다. 이러한 개념을 Vue.js에서도 비슷하게 사용할 수 있습니다.

//NewsView.vue
<template>
    <list-item></list-item>
</template>

<script>
import ListItem from '../components/ListItem.vue'
import bus from '../utils/bus.js';
export default {
    components:{
        ListItem,
    },
    created(){
        bus.$emit('start:spinner');
        this.$store.dispatch('FETCH_NEWS')
        .then(() => bus.$emit('end:spinner'))
        .catch((err) => console.log(err));
    }
}
</script>

//JobsView.vue
<template>
    <list-item></list-item>
</template>

<script>
import ListItem from '../components/ListItem.vue';
import bus from '../utils/bus.js';
export default {
    components:{
        ListItem,
    },
    created(){
        bus.$emit('start:spinner');    
        this.$store.dispatch('FETCH_JOBS')
        .then(() => bus.$emit('end:spinner'))
        .catch((err) => console.log(err));
    }
}
</script>

위의 두 소스코드는 가져오는 데이터만 다르지 그 외의 구조나 로직들은 똑같은 것을 볼 수 있습니다. 이러한 컴포넌트 위에 새로운 컴포넌트를 정의하고 공통된 로직을 모아두는 기법이라고 보면 됩니다.

img

하지만 이러한 HOC는 공통 요소를 뽑아내 코드를 재사용할 수 있다는 장점이 있지만, 많이 사용할 수록 컴포넌트의 레빌이 깊어져서 복잡해진다는 단점이 있습니다.

HOC 컴포넌트 적용

import ListView from './ListView.vue';
import bus from '../utils/bus.js';

export default function createListView(name){
    return{
        //재사용 할 인스턴스(컴포넌트) 옵션들
        name,                                                          (1)
        created(){                                                     (2)
            bus.$emit('start:spinner');    
            this.$store.dispatch('FETCH_LIST', this.$route.name)
            .then(() => bus.$emit('end:spinner'))
            .catch((err) => console.log(err));
        },  
        render(createElement){                                         (3)
            return createElement(ListView);
        }
    }
}

공통된 로직을 처리한 후에 ListView 컴포넌트를 render해주는 형식으로 HOC를 구성하면 됩니다.

export const router = new VueRouter({
    mode: 'history',
    routes:[
        //path : url 주소, component : 페이지에 보여질 컴포넌트
        {
            path: '/',
            redirect: '/news'
        },
        {
            path: '/news',
            name : 'news',
            // component: NewsView,
            component: createListView('NewsView'),
        },
        {
            path: '/jobs',
            name : 'jobs',
            // component: JobsView,
            component: createListView('JobsView'),
        },
        {
            path: '/ask',
            name : 'ask',
            // component: AskView ,
            component: createListView('AskView'),
        },

이렇게 되면 NewsView 안에 ListView - ListItem 으로 컴포넌트 구조가 짜여지는 걸 확인할 수 있습니다. 원래 NewView 밑에 ListView 컴포넌트가 하나 더 생기기 떄문에 많이 사용할 수록 컴포넌트 구조가 깊어질 수 밖에 없습니다.

img

그럼 컴포넌트 깊이가 깊어지지 않고 공통되는 로직을 공통화할 수 없을까?에 대해 물을 수 있습니다. 그러한 부분에 대해서는 mixins라는 기술을 사용할 수 있다고 하는데 관련 내용은 다음번에 포스팅하겠습니다.

728x90
반응형