Week 8. Vue 신세계 탐험(3)
Vue 과제 제출 기한을 맞추기 위해 강의 내용은 간단히 키워드로 정리
일반적으로 지역 등록 권장.
글로벌로 사용할 때만 전역으로.
형태: app 애플리케이션.component(컴포넌트 이름, 옵션)
dash-case
로 작성PascalCase
로 작성template
옵션 사용형태: props: []
html에선 배열 요소를 속성으로 전달
props에선 속성의 값을 받아와서 동적으로 사용
props는 읽기 전용.
👉🏻 외부에서 들어오는 값은 자식요소가 수정할 수 없다...!
props: {데이터: { type: , default: }}
:
로 데이터로써 props에 동적으로 값 전달v-bind
와 함께 객체 전체 전달⚠️ If) 데이터가 상위에서 첫번째 인수로 못 들어간다면 $event
사용
특징
: app.component('컴포넌트 이름', {
props: [],
emits: [event, event2]
}
⚠️ 데이터의 흐름은 단방향으로 흐르게 해, 관리가 용이하게 해야한다.
$attrs
내장 객체가 갖고 있다.$attrs
를 쓰지 않아도 자동으로 속성들이 상속되지만,$attrs
에서 속성들을 가져와야 한다.최상위 요소
: template 태그의 자식 요소 (자손 요소 x)
inheritAttrs: false
!modelValue
: v-model
로 들어온 데이터는 modelValue
props와 연결됨.
👉🏻 props를 양방향 데이터 바인딩 하고 싶을 때 사용
@event="emit('customEvent:modelValue')" // emit과 연결법
<Component v-model:원하는 이름="데이터"/>
<template>
<keep-alive> // 동적 컴포넌트 캐싱
<component :is="currentComponent" />
</keep-alive>
</template>
export default {
data() {
return {
currentComponent: 동적으로 할당할 컴포넌트 이름
}
}
}
⚠️ 동적으로 자주 렌더링되는 동적 컴포넌트만 keep-alive
내부에 넣을 것.
태그 내부 컨텐츠를 가져옴
fallback
contentslot의 넣을 기본 컨텐츠.
컨텐츠가 있을 경우 무시됨.
#
<!--HTML-->
<!--<template v-slot:hello>-->
<template #hello>
<h2>Hello</h2>
<template>
// JS
<template>
<slot name="hello"></slot> // <h2>Hello</h2>가 들어감
</template>
default
slot임.DOM 선택자.
<template>
<h1 ref="선택자 이름"></h1>
</template>
<script>
export default {
mounted() { // mounted 라이프 사이클에서만 동작
console.log(this.$refs.선택자이름)
}
}
</script>
현재 Vue 인스턴스 내에서 ref로 참조하고 있는 요소들이 $refs 객체에 들어있음.
👉🏻 document에서부터 순회하며 찾지 않기 때문에 비용 효율적임.
this.$refs.선택자이름.$el
로 찾아야 함.
⚠️ if) 해당 컴포넌트의 최상위 요소가 여러개일 땐
this.$refs.선택자이름
에서 최상위 요소들에게 또 ref를 달아서 선택해줘야 함.
this.$refs.선택자이름.$refs.최상위요소 선택자이름
데이터가 수정되고 나서 화면이 바뀌는 것을 보장해줌.
데이터가 바뀌자마자 출력되는 html 구조에서 어떤 로직을 실행하고 싶을 때 사용.
this.$nextTick(() => 로직)
export default {
install(app, options) {
app.config.globalProperties.$플러그인 = () =>
}
}
app에 config에 gloalProperteis로 $플러그인
을 등록하겠다!는 의미. 👉🏻 전역 프로퍼티이기 때문에 어디서나 this.$플러그인
으로 접근 가능
등록하는 방법
최상위 js 파일에서
app.use(import한 플러그인 파일 이름, options)
재사용가능한 기능.
지역등록
mixins: [믹스인 이름]
전역등록
app.mixin({})
<teleport to='css 선택자'>
전송할 태그들
</teleport>
teleport로 감싸진 데이터들을 해당 컴포넌트 내부에서 온전히 사용할 수 있으면서도,
css 선택자의 하위 요소로 출력할 수 있음.
조상요소에서 후손요소로 바로 데이터를 주입.
// 보내는 쪽에서
export default {
provide() {
return {
보낼 데이터: this.데이터
}
}
}
// 받는 쪽에서
export default {
inject: ['받을 데이터']
}
⚠️ Provide
로 제공하는 데이터는 반응성을 가지지 않는다.
👇🏻 해결방안
computed
함수를 가져와 (옵션 x) 원하는 곳에서 계산된 데이터를 만들기.
<script>
import { computed } from 'vue'
export default {
provide() {
return {
보낼 데이터: computed(() => this.데이터)
}
}
}
</script>
computed의 콜백함수가 반환하는 데이터가 계산된 데이터로 취급되어 보낼 데이터에 들어감.
computed 함수로 반환된 데이터는 Computed객체 안의 value
로 들어가게 됨.
⭐️ 따라서 inject 쪽에선 데이터.value로 값을 꺼내줘야 함!!!
부모와 자식 간의 데이터 전달: props | $emit
조상과 자손 간의 데이터 전달: provide | inject + computed
그외 데이터 전달: vuex
vuex
: 상태 관리 라이브러리
상태관리
: 모든 데이터 통신을 한 곳에서 중앙집중 관리
mutations
- 동기 로직 및 state 변경 로직action
- 그외 비동기 로직 관리// basic vuex 형태
import {{ createStore }} from 'vuex'
export default createStore({
state() { return {} },
getters: {}, // computed data
mutations: {}, // state 변경 로직, 동기 처리
actions: {} // 그외 비동기 로직
// context => state, getters, commit, dispatch
modules: {}
})
context
가 들어감.state
, getters
, commit
, dispatch
commit
: mutation 실행dispatch
: action 실행프로젝트 규모가 커지면 module로 분리해서 관리하는 것이 용이.
export default {}
namespaced
를 가지면,namespaced: true
모듈의 state 접근법
ex) this.$store.state.네임스페이스.데이터
⚠️ 모듈의 getters 접근법
ex) this.$store.getters['네임스페이스/계산된데이터']
모듈의 mutations 접근법
ex) this.$store.commit('네임스페이스/계산된데이터')
모듈의 actions 접근법
ex) this.$store.dispatch('네임스페이스/계산된데이터')
$store.commit('모듈네임스페이스/메소드이름')
상태가 점점 복잡해지면 mapping으로 간단히 가져올 수 있음!
import { mapState, mapGetters, mapMutations, mapActions } from 'vuex'
export default {
computed: {
...mapState(['상태', '상태',...]) // 전역 state
...mapState('네임스페이스', ['상태', '상태',...]),
...mapGetters('네임스페이스', ['상태', '상태',...]),
},
methods: {
...mapMutations('네임스페이스', ['mutation', 'mutation'...]),
...mapActions('네임스페이스', ['action', 'action'...])
}
}
const path = require('path');
const { VueLoaderPlugin } = require('vue-loader');
const HtmlPlugin = require('html-webpack-plugin');
const CopyPlugin = require('copy-webpack-plugin'); // favicon
module.exports = {
resolve: {
extensions: ['.vue', '.js'], // 생략할 확장자
alias: { // 경로 별칭
'~': path.resolve(__dirname, 'src')
}
},
entry: './src/main.js',
output: {
path: path.resolve(__dirname, 'dist'),
clean: true
},
module: {
rules: [
{
test: /\.vue$/,
use: 'vue-loader'
},
{
test: /\.s?css$/,
use: [ // 먼저 해석이 필요한 로더를 나중에 작성
'vue-style-loader',
'css-loader',
'sass-loader'
]
}
]
},
plugins: [
new VueLoaderPlugin(),
new HtmlPlugin({
template: './src/index.html' // 컴파일할 html 파일
}),
new CopyPlugin({
patterns: [
{ from: 'static' } // 정적 파일 저장할 폴더
]
})
],
}
외울게 점점 많아지지만, 익숙하지 않아서 낯선 느낌?
하지만 Vue로 프로젝트 구조화하는데 있어서
깔끔하게 정리할 수 있다는 생각은 여전히 갖고있다!
Vue랑 잘해보고 싶다!
slot 공부 할 때 활용에 대해서 고민이 많이 들더라고요. 잘 배워갑니다 :)