Vue - Pinia

김영준·2023년 8월 13일
1

TIL

목록 보기
82/91
post-thumbnail

Pinia

Vue의 상태 관리 라이브러리로 State, Getters, Actions의 3가지 개념으로 동작한다.
vuex의 Mutation이 사라지고 modules도 기본적인 구조이므로 관리하지 않아도 된다.

사용법

pinia 설치

npm i pinia

main.ts에 pinia 등록

import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'

createApp(App).use(createPinia()).mount('#app')

store 작성

/src/store/count.js 작성
이 때 count는 모듈이 된다.

import { defineStore } from 'pinia'

// 첫 번째 인수는 store 이름, 두 번째는 옵션들을 추가
// 함수를 반환
export const useCountStore = defineStore('count', {
  state: () => ({
    count: 1
  }),
  getters: {
    double(state) {
      return state.count * 2
    }
  },
  actions: {
    increase() {
      this.count += 1
    },
    decrease() {
      this.count -= 1
    }
  } // context가 없고 this로 모두 접근 가능
})

컴포넌트에서 작성한 store 사용

변수에 가져온 함수를 할당해서 해당 변수로 store를 참조

<script setup lang="ts">
import { useCountStore } from './store/count'

const countStore = useCountStore()
</script>

<template>
  <h1>{{ countStore.count }}</h1>
  <h1>{{ countStore.double }}</h1>
  <button @click="countStore.increase">Increase</button>
  <button @click="countStore.decrease">Decrease</button>
</template>

타입 스크립트 사용해서 store 생성해 보기

// /src/store/movie.ts

import { defineStore } from 'pinia'

export type Movies = Movie[]
export interface Movie {
  Title: string
  Year: string
  imdbID: string
  Type: string
  Poster: string
}

export const useMovieStore = defineStore('movie', {
  state: () => ({
    movies: [] as Movies // 빈 배열은 never 타입으로 인식되기 때문에 단언을 해줌
  }),
  getters: {
    filteredMovies(state) {
      return state.movies
        .filter((movie) => Number(movie.Year) > 2010)
        .sort((a, b) => Number(b.Year) - Number(a.Year))
    }
  },
  actions: {
    async fetchMovies(title: string) {
      const res = await fetch(`https://omdbapi.com/?apikey=7035c60c&s=${title}`)
      const { Search } = await res.json()
      this.movies = Search
    }
  }
})

작성한 store 사용

$reset() 함수를 사용하면 해당 store의 모든 state를 초기화 시킨다.

// App.vue

<script setup lang="ts">
import { ref } from 'vue'
import { useMovieStore } from './store/movie'

const movieStore = useMovieStore()
const title = ref('')

async function searchMovies() {
  await movieStore.fetchMovies(title.value)
  console.log(movieStore.movies)
}
function resetMovies() {
  title.value = ''
  movieStore.$reset() // movieStore가 가지고 있는 모든 state를 초기화
  console.log(movieStore.movies)
}
</script>

<template>
  <input
    v-model="title"
    @keydown.enter="searchMovies" />
  <button @click="searchMovies">Search</button>
  <button @click="resetMovies">Reset</button>
  <ul>
    <li
      v-for="movie in movieStore.filteredMovies"
      :key="movie.imdbID">
      {{ movie.Title }}
      {{ movie.Year }}
    </li>
  </ul>
</template>
profile
꾸준히 성장하는 개발자 블로그

0개의 댓글