Pinia
상태 관리 라이브러리
여러 컴포넌트에서 동일한 값을 가져다 써야 할 때 필요한 곳에서 import를 해서 쓴다.
여러 곳에서 많이 쓴다면 상태를 쓰는 컴포넌트마다 import를 해줘야 하기 때문에
보통 main.js에서 import 한 후 사용한다.
Pinia 설치
npm insatll pinia
Pinia 사용
import { createPinia } from "pinia";
const pinia = createPinia();
main.js
import { createApp } from "vue";
import "./style.css";
import App from "./App.vue";
import { createPinia } from "pinia";
const pinia = createPinia();
const app = createApp(App);
app.use(pinia);
app.mount("#app");
Store
변수를 저장해놓는 곳
state
- 변수 설정
getters
- 변수의 값을 가져오는 곳
actions
- 변수의 값을 바꾸거나 실행시키고 싶은 함수를 등록하는 곳
import { defineStore } from "pinia";
export const useMessageStore = defineStore("message", {
state: () => ({ message: "", count: 0 }),
getters: {
getMessage: (state) => state.message,
getCount: (state) => state.count + 1,
},
actions: {
setMessage(input) {
this.message = this.message + input;
},
},
});
Store 사용
Parents.vue
<script setup>
import { ref } from "vue";
import Child from "./Child.vue";
import { useMessageStore } from "../stores/useMessageStore";
const message = ref('');
const messageStore = useMessageStore();
</script>
<template>
<h1>부모 컴포넌트</h1>
<input type="text" v-model="message">
<button @click="messageStore.setMessage(message)">버튼</button>
<Child></Child>
</template>
<style scope></style>
Child.vue
<script setup>
import { useMessageStore } from "../stores/useMessageStore";
const messageStore = useMessageStore();
</script>
<template>
<h3>자식 컴포넌트</h3>
<p>자식에서 스토어 사용: {{ messageStore.getMessage }}</p>
</template>
<style scope></style>
Store로 로딩 상태 추가
useLoadingStore.js
import { defineStore } from "pinia";
export const useLoadingStore = defineStore("loading", {
state: () => ({ isLoading: false }),
actions: {
startLoading() {
this.isLoading = true;
},
stopLoading() {
this.isLoading = false;
},
},
});
App.vue
<script setup>
import Parents from "./components/Parents.vue";
import { useLoadingStore } from "./stores/useLoadingStore";
const loadingStore = useLoadingStore();
const loadData = async () => {
loadingStore.startLoading();
await new Promise((resolve) => setTimeout(resolve, 3000));
loadingStore.stopLoading();
};
</script>
<template>
<div v-if="loadingStore.isLoading">로딩중</div>
<button @click="loadData">로딩 시작</button>
<div v-if="!loadingStore.isLoading">로딩 끝</div>
</template>
<style scoped></style>
Store로 상품 목록 정보 가져오기
- 상품 목록 정보를 저장하고 있는 store 하나 생성
- Main에서 store의 상품 정보를 가져와서
- Product에 props로 전달
useProductStore.js
import { defineStore } from "pinia";
export const useProductStore = defineStore("products", {
state: () => ({
products: [
{
name: "상품01",
price: 14000,
},
{
name: "상품02",
price: 9000,
},
{
name: "상품03",
price: 21000,
},
],
}),
getters: {
getProducts: (state) => state.products,
},
});
Main.vue
<script setup>
import Product from "./components/Product.vue";
import { useProductStore } from "./stores/useProductStore";
const productStore = useProductStore();
</script>
<template>
<Product :products="productStore.getProducts"></Product>
</template>
<style scope></style>
Product.vue
<script setup>
const props = defineProps({
products: {
type: Object,
required: true,
},
});
</script>
<template>
<div v-for="product in products">
<p>{{ product.name }}</p>
<p>{{ product.price }}</p>
</div>
</template>
<style scope></style>
Store에서 axios로 데이터 가져오기
로딩 상태를 추가하여 axios를 사용해서 데이터를 가져오기
데이터 URL
[
{"name": "상품01", "price": 1000, "seller": "판매자01"},
{"name": "상품02", "price": 2000, "seller": "판매자02"},
{"name": "상품03", "price": 3000, "seller": "판매자03"},
{"name": "상품04", "price": 4000, "seller": "판매자04"}
]
useLoadingStore.js
import { defineStore } from "pinia";
export const useLoadingStore = defineStore("loading", {
state: () => ({ isLoading: false }),
actions: {
startLoading() {
this.isLoading = true;
},
stopLoading() {
this.isLoading = false;
},
},
});
useProductStore.js
import axios from "axios";
import { defineStore } from "pinia";
export const useProductStore = defineStore("product", {
state: () => ({
products: [],
}),
actions: {
async fetchProducts() {
const response = await axios.get(
"https://c228aa9c-c71d-4ea9-ab6c-f8fffbbfe51a.mock.pstmn.io/product/list"
);
this.products = response.data;
},
},
});
Main.vue
onMounted
- vue에서 컴포넌트가 화면에서 사용될 때 실행되는 함수
- 생명주기 훅
<script setup>
import { onMounted } from "vue";
import { useProductStore } from "./stores/useProductStore";
import { useLoadingStore } from "./stores/useLoadingStore";
const loadingStore = useLoadingStore();
const productStore = useProductStore();
// vue에서 컴포넌트가 화면에서 사용될 때 실행되는 함수
// 생명주기 훅
onMounted(async () => {
loadingStore.startLoading();
await productStore.fetchProducts();
loadingStore.stopLoading();
});
</script>
<template>
<div>
<!-- 만약에 로딩 중이면 로딩을 출력 -->
<p v-if="loadingStore.isLoading">Loading...</p>
<!-- 그렇지 않으면 다음 내용이 보이게 -->
<ul v-if="!loadingStore.isLoading">
<li v-for="product in productStore.products" :key="product.id">
{{ product.name }} - {{ product.price }}
</li>
</ul>
</div>
</template>
<style scope></style>
728x90
'FE > Vue.js' 카테고리의 다른 글
[Vue] Vue Router 내비게이션 가드 / 로그인 기능 구현 (pinia-persistedstate) (0) | 2024.12.26 |
---|---|
[Vue] 컴포넌트 간 데이터 주고받기 (Props, Emit) (0) | 2024.12.23 |
[Vue] 데이터 바인딩 (ref, reactive) / 조건문, 반복문 (v-if, v-for) / v-model (0) | 2024.12.20 |
[Vue] Vue Router란? / Vue Router 사용 (router-link, useRouter) (1) | 2024.12.20 |
[Vue] VSCode에서 Vue.js 템플릿 설정 (Vue.js Snippet) (0) | 2024.12.20 |