TIL | [Vue] Vue 간단 요약

noopy·2021년 9월 28일
2

TIL

목록 보기
16/21
post-thumbnail
post-custom-banner

Week 8. Vue 신세계 탐험(3)

Vue 과제 제출 기한을 맞추기 위해 강의 내용은 간단히 키워드로 정리

🍡 컴포넌트

전역과 지역 등록

일반적으로 지역 등록 권장.
글로벌로 사용할 때만 전역으로.

형태: app 애플리케이션.component(컴포넌트 이름, 옵션)

  • 전역 컴포넌트의 이름은 dash-case로 작성
  • 지역 컴포넌트의 이름은 PascalCase로 작성
  • 최상위 컴포넌트가 아닐 경우, html을 연결하지 않고 template 옵션 사용

Props

  • 외부로부터 데이터를 받아 자식 컴포넌트에게 전달

배열로 명시하기

  • 형태: props: []
    html에선 배열 요소를 속성으로 전달
    props에선 속성의 값을 받아와서 동적으로 사용

  • props는 읽기 전용.
    👉🏻 외부에서 들어오는 값은 자식요소가 수정할 수 없다...!

객체로 명시하기

  • 형태: props: {데이터: { type: , default: }}
    객체 리터럴로 명시할 경우 키 값으로 타입을 지정할 수 있음.

동적으로 전달하기

  • : 로 데이터로써 props에 동적으로 값 전달
  • v-bind와 함께 객체 전체 전달
    객체의 속성이 너무 많다면, 데이터에 객체를 전달함으로써
    속성을 다 전달하는 것과 같이할 수 있다.

$emit

  • 컴포넌트 내부에서 컴포넌트 바깥으로 custom event를 만들어 올려줌.

⚠️ If) 데이터가 상위에서 첫번째 인수로 못 들어간다면 $event 사용

  • 컴포넌트 내부에서 emits 옵션으로 custom events 들을 나열할 수 있음.
    특징:
  1. 명시적으로 emit에 등록된 이벤트들 확인 가능
  2. 내장 이벤트와 커스텀 이벤트의 이름이 같을 경우 커스텀 이벤트가 덮어씀
app.component('컴포넌트 이름', {
  props: [],
  emits: [event, event2]
}

⚠️ 데이터의 흐름은 단방향으로 흐르게 해, 관리가 용이하게 해야한다.

$attrs (non-props 속성을 다루는 객체)

  • 컴포넌트의 속성들은 $attrs 내장 객체가 갖고 있다.
    컴포넌트의 최상위 요소가 1개일 땐 $attrs를 쓰지 않아도 자동으로 속성들이 상속되지만,
    최상위 요소가 복수일 땐 $attrs에서 속성들을 가져와야 한다.

최상위 요소: template 태그의 자식 요소 (자손 요소 x)

  • 상속받고 싶지 않을 땐 inheritAttrs: false!

v-model과 modelValue

modelValue: v-model로 들어온 데이터는 modelValue props와 연결됨.
👉🏻 props를 양방향 데이터 바인딩 하고 싶을 때 사용

@event="emit('customEvent:modelValue')" // emit과 연결법
  • modelValue말고 원하는 이름으로 사용
<Component v-model:원하는 이름="데이터"/>

동적으로 컴포넌트 바꾸기

<template>
  <keep-alive> // 동적 컴포넌트 캐싱
  <component :is="currentComponent" />
  </keep-alive>
</template>

export default {
  data() {
    return {
      currentComponent: 동적으로 할당할 컴포넌트 이름
    }
  }
}

⚠️ 동적으로 자주 렌더링되는 동적 컴포넌트만 keep-alive 내부에 넣을 것.

slots

태그 내부 컨텐츠를 가져옴

fallback content

slot의 넣을 기본 컨텐츠.
컨텐츠가 있을 경우 무시됨.

v-slot: slot name

  • slot 맞춤 연결
  • 약어 : #
<!--HTML-->
<!--<template v-slot:hello>-->
<template #hello>
  <h2>Hello</h2>
<template>
// JS
<template>
  <slot name="hello"></slot> // <h2>Hello</h2>가 들어감
</template>

범위가 있는 슬롯: slotProps

  • slot에 속성 값은 slotProps 객체에 들어있음.
  • 구조분해할당을 통해 slotProps 내부의 속성 값을 바로 가져올 수 있음.
  • slot이 한 개만 있을 경우 default slot임.

Refs

DOM 선택자.

<template>
  <h1 ref="선택자 이름"></h1>
</template>

<script>
  export default {
    mounted() { // mounted 라이프 사이클에서만 동작
      console.log(this.$refs.선택자이름)
    }
  }
</script>

현재 Vue 인스턴스 내에서 ref로 참조하고 있는 요소들이 $refs 객체에 들어있음.
👉🏻 document에서부터 순회하며 찾지 않기 때문에 비용 효율적임.

native 태그가 아닌 컴포넌트를 참조할 때

this.$refs.선택자이름.$el 로 찾아야 함.

⚠️ if) 해당 컴포넌트의 최상위 요소가 여러개일 땐
this.$refs.선택자이름 에서 최상위 요소들에게 또 ref를 달아서 선택해줘야 함.
this.$refs.선택자이름.$refs.최상위요소 선택자이름

$nextTick(콜백함수)

데이터가 수정되고 나서 화면이 바뀌는 것을 보장해줌.
데이터가 바뀌자마자 출력되는 html 구조에서 어떤 로직을 실행하고 싶을 때 사용.
this.$nextTick(() => 로직)

🍡 플러그인

export default {
  install(app, options) {
    app.config.globalProperties.$플러그인 = () => 
  }
}

app에 config에 gloalProperteis로 $플러그인을 등록하겠다!는 의미. 👉🏻 전역 프로퍼티이기 때문에 어디서나 this.$플러그인으로 접근 가능

등록하는 방법
최상위 js 파일에서
app.use(import한 플러그인 파일 이름, options)

🍡 믹스인

재사용가능한 기능.

  • 컴포넌트의 옵션들을 믹스인에 저장했다 여기저기 사용할 수 있음.

지역등록, 전역등록

  • 지역등록
    mixins: [믹스인 이름]

  • 전역등록
    app.mixin({})

옵션 병합

  • 컴포넌트에 있는 옵션들과 믹스인의 옵션들은 적절히 병합됨.
  • 중복되면 컴포넌트 옵션이 우선시 됨.

🍡 Teleport

<teleport to='css 선택자'>
  전송할 태그들
</teleport>

teleport로 감싸진 데이터들을 해당 컴포넌트 내부에서 온전히 사용할 수 있으면서도,
css 선택자의 하위 요소로 출력할 수 있음.

🍡 Provide / Inject

조상요소에서 후손요소로 바로 데이터를 주입.

// 보내는 쪽에서
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로 값을 꺼내줘야 함!!!

🍡 Vuex(Store)

부모와 자식 간의 데이터 전달: props | $emit
조상과 자손 간의 데이터 전달: provide | inject + computed
그외 데이터 전달: vuex

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: {}
})

rules

  • createStore 내부에서 state를 가져올 땐 첫번째 인수로 state 가져오기
  • actions은 대부분의 로직을 담당하기 때문에 다른 옵션들에 모두 접근 가능.
    👉🏻 첫번째 인수로 다른 옵션들에 접근할 수 있는 context가 들어감.
    state, getters, commit, dispatch
    - commit: mutation 실행
    - dispatch: action 실행

modules

프로젝트 규모가 커지면 module로 분리해서 관리하는 것이 용이.

  • 모듈은 객체 리터럴로 export
export default {}
  • 모듈 내에서 namespaced를 가지면,
    모듈 외부에서 namespaced로 모듈을 지정할 수 있음.
    namespaced: true
  • 모듈의 state 접근법
    ex) this.$store.state.네임스페이스.데이터

  • ⚠️ 모듈의 getters 접근법
    ex) this.$store.getters['네임스페이스/계산된데이터']

  • 모듈의 mutations 접근법
    ex) this.$store.commit('네임스페이스/계산된데이터')

  • 모듈의 actions 접근법
    ex) this.$store.dispatch('네임스페이스/계산된데이터')

  • module의 action 사용하기
$store.commit('모듈네임스페이스/메소드이름')

mapping

상태가 점점 복잡해지면 mapping으로 간단히 가져올 수 있음!

import { mapState, mapGetters, mapMutations, mapActions } from 'vuex'

export default {
  computed: {
  ...mapState(['상태', '상태',...]) // 전역 state
  ...mapState('네임스페이스', ['상태', '상태',...]),
  ...mapGetters('네임스페이스', ['상태', '상태',...]),
  },
  methods: {
    ...mapMutations('네임스페이스', ['mutation', 'mutation'...]),
    ...mapActions('네임스페이스', ['action', 'action'...])
  }
}

🍡 webpack 설정

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랑 잘해보고 싶다!

profile
💪🏻 아는 걸 설명할 줄 아는 개발자 되기
post-custom-banner

1개의 댓글

comment-user-thumbnail
2021년 10월 12일

slot 공부 할 때 활용에 대해서 고민이 많이 들더라고요. 잘 배워갑니다 :)

답글 달기