[Vue3 - Part3] 인스타그램 프로젝트 만들기2 (Vuex 사용법, PWA 세팅, Composition API)

흑염소·2024년 2월 26일

coding apple - Vue

목록 보기
6/6

📦 Vuex 파트

vue3에서는 composition API 호환성을 고려해 Pinia 사용을 권장하지만 기본적인 상태관리 연습차 vuex를 사용해본다.

Vuex4 설치

npm install vuex@next

세팅

(src/store.js)

import { createStore } from 'vuex'

const store = createStore({
  state(){
    return {
      name: 'kim' // 데이터(state) 보관하고 싶으면 여기에
    }
  },
})

export default store

기본 템플릿 복붙해서 세팅

(main.js)

import store from './store.js'

app.use(store)

main.js에도 전역 상태관리를 위해 store 추가 작업

(컴포넌트)

<h4>안녕{{ $store.state.name }}</h4>

state를 html 상에서 노출하려면 이렇게 사용하면 된다.

mutations

🚩 Vuex는 컴포넌트 안에서 직접 수정하기 금지!!!

물론 수정할 수 있지만 state 관리를 위해서 다른 방법을 권장한다.

  1. 미리 store.js에 수정방법을 정의해두고
  2. 그 방법을 컴포넌트에서 호출시켜 수정해야함
(store.js)

const store = createStore({
  state(){
    return {
      name: 'KIM'
    }
  },
  mutations: {
    setName(state, payload) {
        state.name = 'park'
    }
  }
})

mutations는 state를 변경하는 함수영역이다.
영역 안의 함수는 첫번째 인자로 store state를 받고 두번째 인자로는 컴포넌트에서 호출시 store로 전달하는 파라미터값(payload)를 받는다.

  <button @click="$store.commit('setName')"></button>

mutations는 컴포넌트에서 $store.commit('mutation명')형태로 호출하면 된다.
이게 올바른 vuex 사용법임.

actions

Vuex에서 actions 항목은

  1. ajax 요청하는 곳
  2. 또는 오래 걸리는 작업들

용도로 사용된다.
mutations 안에다가 ajax 요청하지 않는 이유는 state를 바꿀 때, 순차적으로 연달아서 변경하는 경우가 있다.
만약 위 코드가 오래걸린다면 아래 코드에 지연이 발생하고 관리가 어려워짐.
이럴 때를 위한 actions 항목이다.

const store = createStore({
  state(){
    return {
      more: {},
    }
  },
  mutations: {
    setMore(state, data) {
        state.more = data;
    }
  },
  actions: {
    getData(context){
        axios.get('https://codingapple1.github.io/vue/more0.json')
        .then((res)=>{
            context.commit('setMore', res.data)
        })
    }
  }
})

actions에서 axios로 데이터를 받아오고, mutations 함수를 이용해 state에 저장해줬다.
actions에 만든 함수는 인자로 context를 받는다.
context는 store를 뜻함.
store 내부 mutations에 접근하기 위해 context.commit()을 해줘야함.

  <button @click="$store.dispatch('getData')">더보기버튼</button>

actions를 호출하는 함수는 dispatch('actions명')이다.

ajax는 actions에서
state 변경은 mutations 에서

mapState 사용하기

computed() VS methods() 비교

둘다 함수를 다루는 vue 인스턴스 옵션이다.
하지만 두가지로 나뉘었다는건 용도와 역할의 차이가 있다는 것이다.

  • methods : 함수를 사용할 때마다 실행됨
  • computed : 함수를 사용해도 실행되지 않음

무슨 뜻이냐면 computed는 컴포넌트가 실행될 때 내부 값을 읽고 미리 계산을 해둔다.
호출한다고 계산하는 의미가 아니고 호출시 계산된 값을 뱉어내는 역할이다.
반면 methods는 호출시 내부 코드를 작동시키는 개념이다.
즉, 재렌더링의 차이점이 있다.
computed는 state 데이터와 동일하게 취급하면 된다.
(연산결과를 computed에 저장해두면 좋음)

Vuex에서 computed 사용하기

vuex에서 가져온 state 데이터는 호출 네이밍이 굉장히 길다.
$store.state.이름... 지저분하므로 이런 state를 computed에 전부 적어놓고 이름만 가져와서 html에 사용하는 방식으로 많이 쓴다.

computed() {
	name () {
      return this.$store.state.name
    },
    age () {
      return this.$store.state.age
    },
}

함수형태로 state를 저장시키고 return 해준다.

<h3> {{ name }} </h3>
<p> {{ age }} </p>

html 상에서 간단하게 표현 가능.

근데 이것도 길다 싶으면 mapState()를 쓰면 된다.

vuex state 한번에 꺼내쓰려면 ...mapState()

vuex 함수이기 때문에 import 해와야함

import { mapState } from 'vuex'
...

computed() {
    name () {
      return this.$store.state.name
    },
	...mapState(['age', 'likes', 'more']),
}

(다른 computed 함수랑 같이 쓰려면 ... spread operator 붙여야함)

mapState(['state명']) 형태로 원하는거 전부 꺼내와서 사용하면 된다.
굉장히 짧고 간결한 코드로 state 불러올 수 있음!

가져온 state 데이터를 컴포넌트에서 사용할 이름으로 작명하고 싶다면 object 형식으로 가져오면 된다.

computed() {
	...mapState({ 작명 : 'name', }),
}
<h3> {{ 작명 }} </h3>

mapMutations()도 있음

vuex mutations 한번에 꺼내쓰려면 methods에 동일한 방식으로 등록하면 된다.

methods: {
  ...mapMutations(['이름', '이름2'])
}
// <button @click="$store.commit('이름', 10)"></button>
<button @click="이름()"></button>

commit을 대체해서 간단하게 사용 가능함.

Progressive Web App 세팅

  • manifest.json
  • service-worker.js

PWA 구성에 이 두가지가 필요하다.
두개의 파일을 직접 만들지는 않고 라이브러리를 이용해보자.

vue add pwa

vue 공식 라이브러리 중 pwa 기능을 지원하는 라이브러리임.
터미널에 입력해서 설치.

이제 프로젝트를 build할 때 자동으로 위의 두가지 파일을 생성해준다.
npm run build 해서 확인해보자.
생성된 dist 폴더 확인하면 정말 있음.

  1. manifest.json : 앱정보 담는 파일 (이름, 색상, 아이콘, etc...)
  2. service-worker.js : 웹페이지 구동에 필요한 정보 (오프라인에서 여기있는 파일 사용 가능)

PWA 설정 바꾸기

뭔가 세부설정을 수정하고싶으면 직접 manifest.json 파일을 건드리진 않는다.
build할 때마다 새로 생성되기 때문에 직접 건드리진 않는것임.
그래서 설정을 바꾸고 싶으면 루트 위치에 vue.config.js 파일 생성
아래 코드 붙여넣기 하면 된다.

(vue.config.js)

module.exports = {
  pwa: {
    name: '님 앱이름',
    themeColor: '#4DBA87',
    msTileColor: '#000000',
    workboxOptions: {
      exclude: [/\.map$/, /manifest\.json$/, 'index.html']
    }
  }
}

구글의 workbox 라는 라이브러리 사용법대로 설정을 채워주면 되는데
앱의 이름, 색상 등 커스터마이징 가능하고 exclude 항목에는 특정 파일들을 캐싱하기 싫다면(자주 변경되는 것들) 저기다가 입력해주면 된다.

🚀 Composition API

사용법

setup() 안에 코드를 작성하면 된다.
데이터 생성, 조작, methods, hook, computed 등 option API로 사용하던 것들이 모두 가능하다.

데이터 생성하는 법

import { ref } from 'vue';
export default {
  setup() {
    let follower = ref(0);
    return { follower }
  }
}

setup에서 데이터를 만들 때는 reference data type의 약자인 ref() 를 사용해서 데이터를 생성해야한다.
ref()에 담지 않으면 실시간 렌더링이 반영되지 않는다.
생성한 데이터는 return 해줘야 사용 가능하다.

setup()의 파라미터는 첫번째는 props, 두번째는 context를 받아온다.
(context: attrs, slots, emit, 등등)

setup(props, context) {
	...
}

데이터 변경하기

let follower = ref(0);

axios.get('/follower.json').then((a)=>{
    follower.value = a.data;
})

ref()로 감싼 데이터들에 접근하려면 이름 뒤에 value를 꼭 붙여야한다.
이유는 ref()로 감싸면 일종의 object 형태로 만든 것이기 때문임.

Lifecycle Hook 사용

mounted(), created() 같이 기존에 사용하던 라이프사이클 훅은 on을 붙여주면 된다.
on라이프사이클명(()=>{ 실행할코드 })

import { onMounted, onBeforeUpdate } from 'vue';

onMounted(()=>{ 실행할 코드 })
onBeforeUpdate(()=>{ 실행할 코드 })

꼭 API들을 import 해줘야함!

ref()와 reactive()

데이터 만들 때 사용하는 레퍼런스는 ref() 말고도 reactive()도 있다.
원하는 자료같은거 집어 넣을 수 있다.

차이점

  • reactive () : 보통 array, object 집어넣음
  • ref() : 그 나머지 자료형 집어넣음

관습적으로는 이렇게 쓰지만 기능적으로는 큰 차이가 없기 때문에
ref()안에 object, array 넣어도 상관없다.

import { ref, reactive } from 'vue'

let follower = ref(0);
let test = reactive({ name : 'kim' })

이외에도 toRefs()가 있다.

props 사용은 toRefs()

composition API에서 props를 사용하려고 한다.
하지만 기존 방식대로 props를 등록해서 가져오려면 찾지 못한다.
이유는 setup()은 created()와 동일한 라이프사이클이기 때문이다.
이를 위해서 준비된 setup()의 첫번째 인자 props를 받아와서 사용하면 된다.

하지만 props를 그대로 사용하면 reactive한 반응이 안된다.
위에서 말했다시피 setup()에서 사용하는 데이터들은 렌더링을 위해서 ref(), 혹은 reactive()에 담아서 사용하고 있다.
마찬가지로 props도 담아준 뒤 사용해야 한다.
ref()로 각각 하나씩 담아줘도 되지만 대량으로 여러 데이터가 담겨있는 props를 담아주기 위해 사용하는 함수가 toRefs()다.

import { toRefs } from 'vue';

export default {
    setup(props) {
        let { one, two } = toRefs(props);
        (console.log(one.value))
    }
}

접근할 때는 마찬가지로 이름.value 잊지말기.

watch()

let { one, two } = toRefs(props);

watch(one, ()=>{
    // 변경 원하는 코드
})

첫번째 인자에 등록된 데이터를 감시하며 변경이 감지되면 내부 함수를 실행시킨다.

computed()

const 결과 = computed(()=>{ return follower.value.length })

마찬가지로 computed()도 composition API에서 사용 가능하다.

methods()

함수형태로 만들어서 사용하면 된다.
대신 return {} 안에 꼭 뱉어줘야함!

export default {
    setup() {
      function handleclick = () => {}
      
      return { handleClick }
    }
}

useStore() - vuex store 사용법

composition API에서 store 사용하는 방법

  1. useStore 함수 import
  2. 인스턴스를 만들어서 변수에 저장시켜 사용
import { useStore } from 'vuex';

export default {
    setup() {
      let store = useStore();
      console.log(store.state.name)
      console.log(store.commit())
    }
}

간단하다!
대신 vuex4 버전에서는 composition API에서 mapState() 못쓴다.

[참고] 🐞 Vue Devtools

간혹 코드짜다보면 props를 분명 전해줬는데 에러나고 멈추고 하는 경우가 있다.
그 경우 터미널이나 크롬 개발자도구 console 탭으로 들어가면 대부분의 에러는 해결가능한데 조용하게 에러나는 경우도 많음.
예를 들어 라우터 이런 것들은 뭔가 틀려도 에러로 알려주지 않는다.
그래서 크롬 확장프로그램 중에 Vue-devtools를 설치하면 좀 더 자세히 버그나는 부분을 파악가능함.

데브툴 왼쪽은 컴포넌트 안에 무슨 컴포넌트가 있는지 DOM 트리처럼 구조화해서 보여주고
오른쪽은 data, vuex state, props 목록을 보여준다.
굉장히 편리하니 작업시 반드시 설치하기!

profile
매일 TIL 중인 비전공자 프론트 개발자

0개의 댓글