[Vuejs] 숨겨진 Vue 패턴들

Dongmin Jang
6 min readApr 25, 2018

--

Flower on Appletree

아래 동영상을 보면 vue 개발 할 때 알면 도움 될 팁이 7가지 나온다.

이미 사용중인 것도 있고, 아직 적용 안해본 것도 있다.

간단히 적어놓고 나중에 활용하고자 남겨본다.

급하게 빨리감기 버튼으로 코드만 확인하였는데, 여유가 있다면 다 보셔도 좋을 듯하다.

1. Component Registration

폴더내에 있는 vue component 를 global 컴포넌트로 만들기

import Vue from 'vue'
import upperFirst from 'lodash/upperFirst'
import camelCase from 'lodash/camelCase'
const requireComponent = require.context(
'.', false, /base-[\w-].vue$/
)
requireComponent.keys().forEach(fileName => {
// Get component config
const componentConfig = requireComponent(fileName)
// Get PascalCase name of component
const componentName = upperFirst(
camelCase(fileName.replace(/^\.\//, '').replace(/\.\w+$/, ''))
)
// Register component globally
Vue.component(componentName, componentConfig.default || componentConfig)
})

2. Module Registration

vuex module 등록하는 코드

import camelCase from 'lodash/camelCase'
const requireModule = require.context('.', false, /\.js$/)
const modules = {}
requireModule.keys().forEach(fileName => {
// Don't register ths file as a vuex module
if (fileName === './index.js') return
const moduleName = camelCase(fileName.replace(/(\.\/|\.js)/, ''))
modules[moduleName] = {
namespaced: true,
...requireModule(fileName)
}
})
export default modules

위의 코드는 영상속에 나오는 코드이다.
내 경우는 아래와 같이 작성해서 사용하고 있다.

const modules = {}
const requireModule = require.context('./modules', false, /\.js$/)
requireModule.keys().forEach(fileName => {
// Don't register ths file as a vuex module
if (fileName === './index.js') return
const moduleName = fileName.replace(/(\.\/|\.js)/gi, '')
modules[moduleName] = {
...requireModule(fileName).default
}
})
const getDefaultState = () => {}export default {
namespaced: true,
state: () => {
return getDefaultState()
},
actions: {},
mutations: {},
getters: {},
modules,
}

3. Single-Root Components

template 안에 root element 가 하나 있어야만 하는데, 사실 가끔 이게 불필요하게 느껴진다. 괜히 div로 감싸기도 좀 찝찝했는데, functional component 를 이용해서 처리하는 방법이 있다.

<template>
<ul>
<NavBarRoutes :routes="persistentNavRoutes"/>
<NavBarRoutes
v-if="logedIn"
:routes="persistentNavRoutes"
/>
<NavBarRoutes
v-else
:routes="persistentNavRoutes"
/>
</ul>
</template>
[NavBarRoutes component]export default {
functional: true,
render(h, {props}) {
return props.routes.map(route =>
<li key={route.name}>
<router-link to={route}>
{route.title}
</route-link>
</li>
)
}
}

4. Transparent Wrappers

2.4 버전 부터 제공되는 inheritAttrs, $attrs, $listeners를 이용하면 wrapper component 를 쉽게 만들 수 있는데 이 부분을 모르고 있었다.

주의 할 부분은 @focus 부분에 .native를 붙이지 말아야 한다. (자식 컴포넌트에서 $listeners 로 전달 받지 못한다)
<label>을 넣은 이유는 BaseInput component의 root element 를 바꿔서 상황을 만들기 위함으로 보인다.

<BaseInput
placeholder="Waht's your name?"
@focus="doSomething"
/>
[BaseInput component]<template>
<label>
{{ label }}
<input
V-bind="$attrs"
:value="value"
v-on="listeners"
></input>
</label>
</template>
<script>
export default {
inheritAttrs: false,
computed: {
listeners() {
return {
...this.$listeners
input:event =>
this.$emit('input', event.target.value)
}
}
}
}
</script>

--

--