# ๋ทฐ์์ค ํ์ ์ ์ ๋ฐฉ๋ฒ
DANGER
โ ๏ธ ์ฃผ์! ์ด ๊ธ์ Vuex์ ํ์ ์คํฌ๋ฆฝํธ์ ๊ธฐ๋ณธ ๊ฐ๋ ์ ๋ชจ๋ ์์๋ ๋ถ๋ค์ด ์ฝ์ผ์ค ์ ์๋ ๊ธ์ ๋๋ค. ์ธํ๋ฐ Vue.js ํ์ต ๋ก๋๋งต (opens new window)์ ๋ชจ๋ ์๊ฐํ์ ๋ถ๋ค๊ป ์ ํฉํฉ๋๋ค ๐
Vue.extend()
๋ฐฉ์์ ์ด์ฉํ์ฌ ๋ทฐ์์ค๋ฅผ ํ์ดํํ๋ ค๋ฉด ๋ทฐ์์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ด๋ถ์ ์ผ๋ก ์ ๊ณตํ๋ ํ์
์ ์ฝ๊ฐ ๋ณํํด ์ฃผ์ด์ผ ํฉ๋๋ค. ์ฝ๋ ์์ฑ ๋ฐฉ์์ ์์๋ณด๊ธฐ ์ํด ํ ํฐ์ ์ค์ ํ๋ ๋ทฐ์์ค ์ฝ๋๋ฅผ ์์ฑํด ๋ณด๊ฒ ์ต๋๋ค.
# Vuex ๊ธฐ๋ณธ ์ฝ๋
๋จผ์ store/index.ts
์ ์๋์ ๊ฐ์ด ์ ์ํฉ๋๋ค.
// store/index.ts
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
const store = {
state: {
token: ''
}
};
export default new Vuex.Store(store);
# state ์ ์
์ ๊ธฐ๋ณธ ์ฝ๋์์ state
๋ฅผ ๋ณ๋์ ํ์ผ๋ก ๋ถ๋ฆฌํฉ๋๋ค. store/state.ts
์ ๋๊ฒ ์ต๋๋ค.
// store/state.ts
export const state = {
token: '',
}
export type RootState = typeof state;
state
๋ฅผ ์ ์ํ ๋ค์ ํด๋น ๊ฐ์ฒด ๊ตฌ์กฐ์ ํ์
์ RootState
์ ํ์
๋ณ์๋ก ์ ์ธํฉ๋๋ค.
# mutations ์ ์
๋ฎคํ
์ด์
์ฝ๋๋ store/mutations.ts
ํ์ผ์ ๋ณ๋๋ก ์์ฑํฉ๋๋ค.
// store/mutations.ts
import { RootState } from "./state";
// ๋ฎคํ
์ด์
ํ์
export enum MutationTypes {
SET_TOKEN = "SET_TOKEN",
}
// ๋ฎคํ
์ด์
์์ฑ ํจ์
export const mutations = {
[MutationTypes.SET_TOKEN](state: RootState, token: string) {
state.token = token;
},
};
export type Mutations = typeof mutations;
์ถํ ๋ฎคํ
์ด์
์์ฑ ํจ์์ ํ์
์ถ๋ก ์ ์ํด ๋ฎคํ
์ด์
ํจ์์ ์ด๋ฆ์ ๋ชจ๋ enum
๊ฐ์ผ๋ก ์ ์ธํ๊ณ ํด๋น ๊ฐ์ ํจ์์ ์ด๋ฆ์ผ๋ก ์ ์ํด ์ค๋๋ค. ์์์ ์ ์ํ state
์ ํ์
์ธ RootState
๋ฅผ ๋ค๊ณ ์์ ๋ฎคํ
์ด์
์์ฑ ํจ์์ ์ฒซ ๋ฒ์งธ ํ๋ผ๋ฏธํฐ ํ์
์ผ๋ก ์ฐ๊ฒฐํด ์คฌ์ต๋๋ค.
# ๋ทฐ ์ปดํฌ๋ํธ์์ ํ์ฉํ ์ ์๋๋ก ๋ทฐ์์ค ์ปค์คํ ํ์ ์ ์
๊ธ ์๋์ ์ธ๊ธํ ๊ฒ์ฒ๋ผ ๋ทฐ์์ค์ ๋ด๋ถ ํ์
๋ฐฉ์์ผ๋ก๋ ์์์ ์ ์ํ state
์ mutations
๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ์ถ๋ก ๋์ง ์์ต๋๋ค. ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด store/types.ts
์ ์๋์ ๊ฐ์ด ์์ฑํฉ๋๋ค.
// store/types.ts
import { CommitOptions, Store } from "vuex";
import { Mutations } from "./mutations";
import { RootState } from "./state";
type MyMutations = {
commit<K extends keyof Mutations, P extends Parameters<Mutations[K]>[1]>(
key: K,
payload?: P,
options?: CommitOptions
): ReturnType<Mutations[K]>;
};
export type MyStore = Omit<
Store<RootState>,
"commit"
> &
MyMutations
์ ์ฝ๋๋ ๋ทฐ์์ค ๋ด๋ถ์ ์ผ๋ก ์ ์๋ ํ์
์ ์ฐ๋ฆฌ๊ฐ ์ ํ๋ฆฌ์ผ์ด์
์์ ์ฌ์ฉํ๊ธฐ ์ํด ์์ฑํ state
, mutations
ํ์
์ฝ๋๋ฅผ ์ถ๊ฐํ ์ฝ๋์
๋๋ค. ์๋ก ์ ์๋ MyStore
ํ์
์ ์ด์ ํ๋ก์ ํธ์์ ์ธ์ํ ์ ์๊ฒ๋ง ํด์ฃผ๋ฉด ๋ฉ๋๋ค.
TIP
๋ทฐ์์ค ๋ด๋ถ ํ์
์ด ๊ถ๊ธํ์ ๋ถ๋ค์ Store
ํ์
์ ์ซ์์ ๋ค์ด๊ฐ๋ณด์ธ์ ๐
# ํ๋ก์ ํธ ํ์ ์ ์ ํ์ฅํ๊ธฐ
์ด์ ์์์ ์ ์ํ MyStore
ํ์
์ ์๋์ ๊ฐ์ด ์ปดํฌ๋ํธ ์ต์
์์ฑ์์ ์ถ๋ก ๋ ์ ์๊ฒ ํด๋ณด๊ฒ ์ต๋๋ค.
๋ทฐ + ํ์
์คํฌ๋ฆฝํธ ํ๋ก์ ํธ ๋ฃจํธ ๋ ๋ฒจ์ src/types/project.d.ts
ํ์ผ์ ์์ฑํ๊ณ ์๋ ๋ด์ฉ์ ์์ฑํฉ๋๋ค.
// src/types/project.d.ts
import Vue from "vue";
import { MyStore } from "../store/types";
declare module "vue/types/vue" {
interface Vue {
$store: MyStore;
}
}
declare module "vue/types/options" {
interface ComponentOptions<V extends Vue> {
store?: MyStore;
}
}
๋ค์์ผ๋ก ํ๋ก์ ํธ์ ํ์ ์คํฌ๋ฆฝํธ ์ค์ ํ์ผ์ ์๋ ์ต์ ์ ์ถ๊ฐํฉ๋๋ค.
// ...
"include": [
"src/**/*.ts",
"src/**/*.tsx",
"src/**/*.vue",
"tests/**/*.ts",
"tests/**/*.tsx",
"src/types/**.d.ts",
],
"exclude": [
// ...
]
๊ทธ๋ฆฌ๊ณ node_modules/vuex/types/vue.d.ts
ํ์ผ์ ์ญ์ ํฉ๋๋ค. ์ด์ ์ฌ์ฉ์ค์ธ ๊ฐ๋ฐ ํด์ด๋ ์ฝ๋ ํธ์ง๊ธฐ๋ฅผ ์ข
๋ฃํ๊ณ ๋ค์ ์คํํ์ฌ ์ถ๋ก ์ด ์ ๋๋์ง ํ์ธํฉ๋๋ค.
TIP
Vue 2์์๋ node_modules ๋ฐ์ ํ์ ์ ์ธ ํ์ผ์ ์ง์์ค์ผ ํ์ง๋ง, Vue 3์์๋ ๋ด๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๊ฑด๋ค์ง ์๊ณ ๋ ํ์ฅํ ์ ์๊ฒ ๋ค์๊ณผ ๊ฐ์ ์ธํฐํ์ด์ค๊ฐ ์ ๊ณต๋ฉ๋๋ค ๐ Vuex 4 ๋ฆด๋ฆฌ์ฆ ๋ ธํธ (opens new window)
# actions ์ ์
actions
ํจ์๋ ์๋์ ๊ฐ์ด ์ ์ํ ์ ์์ต๋๋ค.
// store/actions.ts
import { ActionContext } from "vuex";
import { Mutations } from "./mutations";
import { RootState } from "./state";
export enum ActionTypes {
FETCH_NEWS = "FETCH_NEWS"
}
interface News {
title: string;
id: number;
}
type MyActionContext = {
commit<K extends keyof Mutations>(
key: K,
payload?: Parameters<Mutations[K]>[1]
): ReturnType<Mutations[K]>;
} & Omit<ActionContext<RootState, RootState>, "commit">;
export const actions = {
async [ActionTypes.FETCH_NEWS](context: MyActionContext, payload?: number) {
const res = await fetch("https://jsonplaceholder.typicode.com/users/1");
const user: News[] = await res.json();
return user;
}
};
export type Actions = typeof actions;
์คํ ์ด ์ปค์คํ ํ์ ์ด ์ ์๋ ํ์ผ์ ์๋ ๋ด์ฉ์ ์ถ๊ฐํฉ๋๋ค.
// store/types.ts
import { CommitOptions, DispatchOptions, Store } from "vuex";
import { Actions } from "./actions";
import { Mutations } from "./mutations";
import { RootState } from "./state";
type MyMutations = {
commit<K extends keyof Mutations, P extends Parameters<Mutations[K]>[1]>(
key: K,
payload?: P,
options?: CommitOptions
): ReturnType<Mutations[K]>;
};
type MyActions = {
dispatch<K extends keyof Actions>(
key: K,
payload?: Parameters<Actions[K]>[1],
options?: DispatchOptions
): ReturnType<Actions[K]>;
};
export type MyStore = Omit<
Store<RootState>,
"commit" | "dispatch"
> &
MyMutations &
MyActions;
# getters ์ ์
getters
์์ฑ ํจ์๋ ๋ค์๊ณผ ๊ฐ์ด ์ ์ํฉ๋๋ค.
// store/getters.ts
import { RootState } from "./state";
export const getters = {
getToken(state: RootState) {
return state.token + "!";
}
};
export type Getters = typeof getters;
์คํ ์ด ์ปค์คํ ํ์ผ์ ์๋์ ๊ฐ์ด ์ถ๊ฐํฉ๋๋ค.
import { Action, CommitOptions, DispatchOptions, Store } from "vuex";
import { Actions } from "./actions";
import { Getters } from "./getters";
import { Mutations } from "./mutations";
import { RootState } from "./state";
type MyMutations = {
commit<K extends keyof Mutations, P extends Parameters<Mutations[K]>[1]>(
key: K,
payload?: P,
options?: CommitOptions
): ReturnType<Mutations[K]>;
};
type MyActions = {
dispatch<K extends keyof Actions>(
key: K,
payload?: Parameters<Actions[K]>[1],
options?: DispatchOptions
): ReturnType<Actions[K]>;
};
type MyGetters = {
getters: {
[K in keyof Getters]: ReturnType<Getters[K]>;
};
};
export type MyStore = Omit<
Store<RootState>,
"getters" | "commit" | "dispatch"
> &
MyMutations &
MyActions &
MyGetters;
โ Vue Property Decorator ref โ