728x90
반응형
요즘 프론트엔드 개발 트랜드에서 스토어는 빼놓을 수 없는 개념입니다. Redux, Vuex… 여러 스토어들을 많이 들어봤을 거에요. 아.. 복잡하다… ㅜㅜ 하지만 우리에겐 🎉pinia🎉가 있습니다. 제가 살면서 본 스토어 중에 제일 쉬워요. 무려 dispatch가 없어요…!!! 진작 이렇게 좀 만들지.
- pinia를 설치해봅시다. 아래 명령어를 터미널에 입력해주세요.
yarn add pinia @pinia/nuxt --save-dev
- yarn으로 설치하는 이유는 npm으로 설치하면 pinia와 @pinia/nuxt 간의 의존성이 잡혀 있지 않아 에러가 뜹니다. Nuxt는 yarn에 최적화 되어 있습니다. 하지만 우리는 기본에 충실하기 위해 npm을 사용해봐야해요.. ㅜㅜ 그래서
- 생성된 yarn.lock 삭제
- 터미널에 npm install 실행
- 혹시 npm install 이 안된다면 npm install --legacy-peer-deps 를 입력해주세요.
- 이제 pinia를 사용하기 위해 nuxt에 등록을 해줄겁니다.
- nuxt.config.ts에 아래 코드를 입력해주세요.
// <https://nuxt.com/docs/api/configuration/nuxt-config>
export default defineNuxtConfig({
modules: [
[
"@pinia/nuxt",
{
autoImports: [
// automatically imports `defineStore`
"defineStore", // import { defineStore } from 'pinia'
],
},
],
],
});
- root 위치에 plugins폴더 생성 > pinia.ts 생성 > 아래 코드 입력
import { PiniaPlugin, PiniaPluginContext } from "pinia";
// pinia에서 초기화 할 때 실행해줄 함수
function MyPiniaPlugin({ store }: PiniaPluginContext) {
store.$subscribe((mutation) => {
// 스토어 값이 바뀔 때 로그 찍어줌
if (process.env.MODE === "dev")
console.log(`[🍍 ${mutation.storeId}]: ${mutation.type}.`);
});
// 생성된 시간 리턴해줌
return { creationTime: new Date() };
}
// plugins 폴더에선 defineNuxtPlugin 함수를 사용해 플러그인을 등록합니다.
export default defineNuxtPlugin(({ $pinia }) => {
$pinia.use(({ store }: PiniaPlugin & { store: any }) => {
// 라우터를 피냐의 플러그인으로 넣음(정해진 문법이니 따라 작성해주세요)
const router = useRouter();
store.router = markRaw(router);
});
// 피냐에 플러그인 등록해줌
$pinia.use(MyPiniaPlugin);
});
- plugins 폴더에는 pinia에서 사용할 라이브러리를 등록해줍니다. (pinia, i18n 등등…)
- 포스트에서 사용할 타입을 생성해줍시다.
- types 폴더 생성 > stores 폴더 생성 > postStore.d.ts 생성 > 아래 코드 입력
export interface Post {
id: number;
author: string;
title: string;
contents: string;
}
- 이제 스토어를 만들어봅시다. root 위치에 stores 폴더 생성 > usePostStore.ts 생성 > 아래 코드 입력
- use~의 모양새가 리액트의 훅과 비슷하죠? 피냐에선 각 스토어를 훅과 같은 개념을 불러와 사용합니다.
import type { Post } from "@/types/stores/postStore";
export default defineStore("post", {
state: () => ({
posts: [
{
id: 1,
author: "foo",
title: "첫번째 게시글!",
contents: "첫번째 게시글 내용!",
},
{
id: 2,
author: "foo",
title: "세상에서 제일 귀여운 고양이",
contents: "구라얌",
},
] as Post[],
}),
getters: {
// 포스트가 존재하면 첫번째 포스트 가져옴
firstPost: (state): Post | boolean => {
if (state.posts.length) return state.posts[0];
else return false;
},
},
actions: {
// Posts 할당
setPosts(posts: Post[]) {
this.posts = posts;
},
},
});
- Pinia의 state, gettres, actions
- state: 변수입니다. 반응성을 가지며 actions로 변경하거나 pinia에 바로 접근해서 변경할 수 있습니다.
- getters: vue의 computed와 비슷합니다. 함수를 미리 계산해 변수에 저장하는 형태로 연산 횟수를 줄이고 더 편하게 사용할 수 있습니다.
- actions: state를 변경하기 전에 하고 싶은 로직을 넣습니다. this(store)에 접근할 수 있습니다.
- pages/posts/index.vue에 아래 코드 입력
<template>
<div class="posts">
<h1>Posts Page</h1>
<template v-for="post of postStore.posts">
<div class="post" @click="$router.push(`/posts/${post.id}`)">
<h3>{{ post.id }}</h3>
<h3>{{ post.title }}</h3>
</div>
</template>
</div>
</template>
<script setup lang="ts">
import usePostsStore from "@/stores/usePostStore";
const postStore = usePostsStore();
</script>
<style lang="scss" scoped>
.post {
display: flex;
gap: 8px;
align-items: center;
cursor: pointer;
&:hover {
opacity: 0.8;
}
}
</style>
- pinia는 반응성을 보장하며 스토어에서 직접 state를 가져올 수도 있고 state를 수정할 수도 있습니다. dispatch가 필요 없어요. 말도 안돼…
- pages/posts/[id].vue 생성 > 아래 코드 입력
<template>
<div class="post">
<h1>Post</h1>
<NuxtLink to="/posts">뒤로 가기</NuxtLink>
<h2>id: {{ post.id }} title: {{ post.title }}</h2>
<div class="post-contents">{{ post.contents }}</div>
</div>
</template>
<script setup lang="ts">
import usePostStore from "@/stores/usePostStore";
import { storeToRefs } from "pinia";
// 라우터 객체
const route = useRoute();
const router = useRouter();
// 스토어에서 포스트 가져옴
const postStore = usePostStore();
const { posts } = storeToRefs(postStore);
// 포스트를 변수에 저장
const postId = parseInt(route.params.id as string) - 1;
const post = ref(posts.value[postId]);
// 포스트가 없으면 예외처리로 홈으로 보냄
if (!post.value) router.push("/");
</script>
<style lang="scss" scoped>
.post-contents {
border: 1px solid black;
border-radius: 4px;
min-height: 600px;
padding: 1rem;
}
</style>
- 스토어에서 값을 가져와서 포스트에 넣었습니다. 이제 각 아이디의 포스트 내용을 보실 수 있습니다.
- storeToRefs 는 스토어의 모든 state를 가져와서 ref로 감싸주는 함수입니다. 각 state가 ref변수로 나온다고(구조 분해 된다고) 생각하시면 됩니다. (const { posts, …state 안의 변수들 } = storeToRefs(store변수)
stores 끝!
728x90
반응형