가수면
[Vue] 전역 상태 관리 본문
Vuex
타입스크립트 적용
1. vuex 타입 에러 문제
공식 문서에 따르면 특별한 TypeScript 구성이 필요하지 않다고 하는데 모듈 선언에 대한 오류가 발생할 수 있다.
import { createStore } from "vuex";
모듈 'vuex'에 대한 선언 파일을 찾을 수 없습니다. 'c:/Users/yhhnn/Desktop/dev/frontend/Private/Vue/weather/node_modules/vuex/dist/vuex.mjs'에는 암시적으로 'any' 형식이 포함됩니다.
There are types at 'c:/Users/yhhnn/Desktop/dev/frontend/Private/Vue/weather/node_modules/vuex/types/index.d.ts', but this result could not be resolved when respecting package.json "exports". The 'vuex' library may need to update its package.json or typings.
이 경우 그냥 모듈의 타입 선언을 우회하는 편법을 사용해 해결할 수 있다.
// src\@types\모듈명\index.d.ts
declare module "모듈명";
2. $store로 사용 시 타입 에러 문제
{{ $store?.state?.count }}
'CreateComponentPublicInstance<Readonly<ExtractPropTypes<{}>>, { Navbar: DefineComponent<{}, {}, {}, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, ... 5 more ..., {}>; MainComp: DefineComponent<...>; weatherData: Ref<...>; onSearchCity: (inputText: string) => void; }, ... 17 more ..., {}>' 형식에 '$store' 속성이 없습니다.
이 경우 전역 선언을 통해 해결할 수 있다.
// src\store\vuex.d.ts
import { Store } from "vuex";
declare module "@vue/runtime-core" {
interface State {
count: number;
}
interface ComponentCustomProperties {
$store: Store<State>;
}
}
3. useStore를 사용할 때 타입 에러 문제
import { useStore } from "vuex/types/index.js";
[plugin:vite:import-analysis] Failed to resolve import "vuex/types/index.js" from "src/App.vue". Does the file exist?
useStore를 스토어에 직접 선언하고 export해 해결할 수 있다.
// src\store\store.ts
import { InjectionKey } from "vue";
import { createStore, useStore as baseUseStore } from "vuex";
import { Store } from "vuex/types/index.js";
export interface State {
count: number;
}
export const store = createStore({
state: {
count: 0,
},
mutations: {
addCount(state: State, payload: number) {
state.count += 1 + payload;
},
},
});
export const key: InjectionKey<Store<State>> = Symbol();
export function useStore() {
return baseUseStore(key);
}
// src\main.ts
import { store, key } from "./store/store";
createApp(App).use(store, key)
기본 사용법
$store 사용
$store?.commit(mutations 함수명, payload)
<p>count : {{ $store?.state?.count }}</p>
<button @click="$store?.commit('addCount', 10)">증가</button>
useStore 사용
<script setup lang="ts">
import { useStore } from "./store/store";
const store = useStore();
</script>
...
<p>count : {{ store?.state?.count }}</p>
<button @click="store?.commit('addCount', 10)">증가</button>
actions
비동기적인 작업을 할 때는 actions를 이용해 mutations, state를 변경
Pinia
store
스토어 내에서 상태 및 actions 사용 시 this
비동기 actions 함수에는 async/await 사용
import { defineStore } from "pinia";
export const useStore = defineStore("weather", {
state: () => ({
weatherData: {
icon: "icon",
temp: 0,
text: "text",
location: "location",
city: "Seoul",
},
}),
actions: {
updateWeather(payload: any) {
this.weatherData.icon = payload.weather[0].icon;
this.weatherData.temp = payload.main.temp;
this.weatherData.text = payload.weather[0].description;
this.weatherData.location = payload.sys.country;
this.weatherData.city = payload.name;
},
onSearchCity(payload: string) {
this.weatherData.city = payload;
},
async getWeather() {
const API_URL = `https://api.openweathermap.org/data/2.5/weather?q=${this.weatherData.city}&appid=050d4b026cee0fc9716845267b7b107c`;
await fetch(API_URL)
.then((res) => res.json())
.then((data) => {
this.updateWeather(data);
})
.catch(() => alert("날씨를 불러오는 데 실패했습니다."));
},
},
});
사용
상태값 사용 - storeToRefs와 스토어에서 export한 defineStore 사용
useStore에서 직접 사용해도 되지만, storeToRefs를 이용해 상태값을 사용하는 것이 직접 사용하는 것보다 Vue의 반응형 시스템과 잘 통합되어 있기 때문에 안전하다.
또한, storeToRefs로 전역 상태값을 사용하는 것이 props로 전달하는 방식에 있어 더 적합하다.
<template>
<div class="weather-info">
<div class="icon"><img :src="`https://openweathermap.org/img/wn/${weatherData.icon}@2x.png`" alt="날씨 아이콘" /></div>
<div class="temp">{{ (weatherData.temp - 273.15).toFixed(1) }}°</div>
<div class="text">{{ weatherData.text }}</div>
<div class="location">{{ weatherData.city }} ,{{ weatherData.location }}</div>
</div>
</template>
<script setup lang="ts">
import { storeToRefs } from "pinia";
import { useStore } from "../store/store";
const store = useStore();
const { weatherData } = storeToRefs(store);
</script>
함수 사용
defineStore에서 바로 사용
<script setup lang="ts">
import Navbar from "./components/Navbar.vue";
import MainComp from "./components/MainComp.vue";
import { onMounted } from "vue";
import { useStore } from "./store/store";
const store = useStore();
onMounted(() => {
store.getWeather();
});
</script>
'Vue' 카테고리의 다른 글
Vuetify 컴포넌트 자식 요소의 스타일 커스텀하는 방법 (0) | 2024.08.26 |
---|---|
[Vue] 심화 (0) | 2024.05.25 |
[Vue] Router (0) | 2024.05.16 |
[Vue] Composition API 방식 (0) | 2024.05.13 |
[Vue] 기본 (0) | 2024.05.13 |
Comments