Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Vue.js 状態管理の選択肢 - そのVuex本当に必要ですか - / Vue.js Sta...
Search
ryo
March 17, 2021
Technology
4.8k
7
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Vue.js 状態管理の選択肢 - そのVuex本当に必要ですか - / Vue.js State Management Options
iCARE Dev Meetup #19 2021/03/17
ryo
March 17, 2021
More Decks by ryo
See All by ryo
Bridging Social Graphs
kawamataryo
0
350
Raycast AI APIを使ってちょっと便利なAI拡張機能を作ってみた
kawamataryo
1
600
退屈なことはDevinにやらせよう〜〜Devin APIを使ったVisual Regression Testの自動追加〜
kawamataryo
5
2.3k
SaaS公式MCPサーバーをリリースして得た学び
kawamataryo
7
2.2k
Raycast AI APIを使ってちょっと便利な拡張機能を作ってみた / created-a-handy-extension-using-the-raycast-ai-api
kawamataryo
1
910
ts-morphのパフォーマンス改善Tips
kawamataryo
0
140
webpack to Rspack
kawamataryo
0
140
GitHub Actions と Datadog でコードベースの定点観測
kawamataryo
7
2.1k
個人開発駆動学習 / personal development driven learning
kawamataryo
1
320
Other Decks in Technology
See All in Technology
TinyGo 開発サイクルを高速化する:Go で作るエミュレータ入門
zozotech
PRO
1
730
すぐできる衛星通信対応 あとは山奥に行くだけ
tatetate55
0
120
Amazon Quick on DesktopがIAM Identity Centerで動かない理由
yukiogawa
0
190
AIエージェントの自己改善をどう設計するか / How to Design Self-Improvement for AI Agents
22mi
23
15k
OpenTelemetryのメトリクスをCloudWatchに送ってPromQLで見てみた
ota1022
0
150
LTのテーマ どうきめてる?〜5つの型と私のやり方〜
yama3133
1
100
Podは生きているのにGoだけが落ちる:GOGCとGOMEMLIMITで追うInvisible OOM Killの謎
tkc66buzz
1
730
Adaptive Warehouse を今すぐ導入すべき理由と迷ったときの判断基準
__allllllllez__
0
230
登壇の自信を奪う3匹のオバケ / 3 Ghosts That Rob You of Your Confidence in Public Speaking
pauli
8
890
Spring BootからQuarkusへの移行
tatsuya1bm
2
110
10Xに技術的負債をもたらした「2つの境界の歪み」その構造と解消への営み
10xinc
0
1.9k
「守り」で活用するオンデバイスLLM 〜写ってはいけないを総力戦で防ぐ〜 / iOSDC Japan 2026
nakamuuu
0
150
Featured
See All Featured
How to build an LLM SEO readiness audit: a practical framework
nmsamuel
1
900
Making the Leap to Tech Lead
cromwellryan
135
10k
The Director’s Chair: Orchestrating AI for Truly Effective Learning
tmiket
1
300
Designing Dashboards & Data Visualisations in Web Apps
destraynor
232
55k
Agile Leadership in an Agile Organization
kimpetersen
PRO
0
230
Heart Work Chapter 1 - Part 1
lfama
PRO
10
36k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
32
4.8k
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
333
23k
Build The Right Thing And Hit Your Dates
maggiecrowley
39
3.4k
Imperfection Machines: The Place of Print at Facebook
scottboms
270
14k
The Invisible Side of Design
smashingmag
301
52k
Are puppies a ranking factor?
jonoalderson
2
3.9k
Transcript
Vue.js ঢ়ଶཧͷબࢶ ʙ ͦͷVuexຊʹඞཁͰ͔͢? ʙ @KawamataRyo 2021/03/17 iCARE Dev Meetup
#19
ࣗݾհ
@KawamataRyo LAPRAS גࣜձࣾ TypeScript, Vue, Firebase, Ruby ݩফ࢜🔥🚒
ࠓ͢͜ͱ
Vuex + α ͷঢ়ଶཧख๏ͷհ ͦΕͧΕͷ Pros/Cons ͷ·ͱΊ
ͳͥঢ়ଶཧΛςʔϚʹʁ🤔
Vuex ݏΘΕ͗͢͡Όͳ͍͔..?
Vuex 😭 🐵 🐶 😼 🦁 🐯 🐻 🐹 🦊
ͦΕͬͯຊʹVuexͷͳͷͩΖ͏͔ʁ
VuexΛ దʹར༻Ͱ͖ͯͳ͍ or దͳॴͰར༻Ͱ͖ͯͳ͍ ߹͋Δͷ͔ʁ
VuexΛ దʹར༻Ͱ͖ͯͳ͍ or దͳॴͰར༻Ͱ͖ͯͳ͍ ߹͋Δͷ͔ʁ
Vuex Ҏ֎ͷঢ়ଶཧΛΔ͜ͱͰ ঢ়ଶཧͷબࢶΛ͍͛ͨ
ঢ়ଶཧͷجຊ
ͦͦঢ়ଶཧͱʁ
ΞϓϦ͕࣋ͭ ঢ়ଶʢσʔλʣΛదʹѻ ͍ΞϓϦΛਖ਼͘͠ಈ࡞ͤ͞ Δํ๏
ͳͥঢ়ଶཧϥΠϒϥϦ͕ඞཁʁ
ίϯϙʔωϯτ͕૿͑Δͱ Props/EmitͰͷঢ়ଶͷ ͕ෳࡶʹ..
ೝূใͳͲෳίϯϙʔωϯτ Ͱڞ௨ͷσʔλɾϩδοΫΛ࣋ͪ ͍ͨ..
ෳͷίϯϙʔωϯτ͔Β ΞΫηεͰ͖Δάϩʔόϧͳ ঢ়ଶ͕ඞཁ => ঢ়ଶཧϥΠϒϥϦ
ঢ়ଶཧͷબࢶ
Vuex Pinia Vue Apollo Composition API Store
Vuex Pinia Vue Apollo Composition API Store
- Vueެࣜͷঢ়ଶཧϥΠϒϥϦ - FluxϥΠΫ - ୯Ұ Store vuejs / vuex
(v4)
Store import { InjectionKey } from "vue"; import { createStore,
Store } from "vuex"; export interface State { count: number; } export const key: InjectionKey<Store<State>> = Symbol(); export const store = createStore<State>({ state: { count: 0 }, mutations: { increment(state) { state.count++; }, decrement(state) { state.count--; } }, actions: { increment({ commit }) { commit("increment"); }, decrement({ commit }) { commit("decrement"); } } });
Store import { InjectionKey } from "vue"; import { createStore,
Store } from "vuex"; export interface State { count: number; } export const key: InjectionKey<Store<State>> = Symbol(); export const store = createStore<State>({ state: { count: 0 }, mutations: { increment(state) { state.count++; }, decrement(state) { state.count--; } }, actions: { increment({ commit }) { commit("increment"); }, decrement({ commit }) { commit("decrement"); } } }); createStoreͰstoreΛఆٛ mutations, actionsͰstateΛૢ࡞
Store import { InjectionKey } from "vue"; import { createStore,
Store } from "vuex"; export interface State { count: number; } export const key: InjectionKey<Store<State>> = Symbol(); export const store = createStore<State>({ state: { count: 0 }, mutations: { increment(state) { state.count++; }, decrement(state) { state.count--; } }, actions: { increment({ commit }) { commit("increment"); }, decrement({ commit }) { commit("decrement"); } } }); provide/inject༻ͷΩʔ ʢTSͷܕఆٛऔಘͷͨΊʣ
Install import { createApp } from "vue"; import App from
"./App.vue"; import { store, key } from "./stores/vuex/store"; const app = createApp(App); // vuex app.use(store, key); app.mount("#app");
Install import { createApp } from "vue"; import App from
"./App.vue"; import { store, key } from "./stores/vuex/store"; const app = createApp(App); // vuex app.use(store, key); app.mount("#app"); storeͱkeyΛొ
Components (read) <script lang="ts"> import { defineComponent, computed } from
"vue"; import { useStore } from "vuex"; import { key } from "@/stores/vuex/store"; export default defineComponent({ name: "Counter", setup() { const store = useStore(key); const count = computed(() => store.state.count); return { count }; } }); </script>
Components (read) <script lang="ts"> import { defineComponent, computed } from
"vue"; import { useStore } from "vuex"; import { key } from "@/stores/vuex/store"; export default defineComponent({ name: "Counter", setup() { const store = useStore(key); const count = computed(() => store.state.count); return { count }; } }); </script> keyΛͯ͠storeΛऔಘ countnumberܕͱͯ͠ਪ
<script lang="ts"> import { defineComponent } from "vue"; import {
useStore } from "vuex"; import { key } from "@/stores/vuex/store"; export default defineComponent({ name: "IncrementButton", setup() { const store = useStore(key); const increment = () => store.dispatch("increment"); return { increment }; } }); </script> Components (write)
<script lang="ts"> import { defineComponent } from "vue"; import {
useStore } from "vuex"; import { key } from "@/stores/vuex/store"; export default defineComponent({ name: "IncrementButton", setup() { const store = useStore(key); const increment = () => store.dispatch("increment"); return { increment }; } }); </script> Components (write) dispatchͰactionsΛ࣮ޮ ܕิޮ͔ͳ͍
- ެࣜϥΠϒϥϦ - υΩϡϝϯτɾࢀߟใͷ๛͞ - DevToolsͷ࿈ܞ - ߏԽ͞ΕͨύλʔϯʢFluxʣ - SSRରԠ
Pros 😁
- TypeScriptͷܕ͚ͷରԠ - هड़ྔͷଟ͞ Cons 😵
Vuex Pinia Vue Apollo Composition API Store
- Composition APIઐ༻ - ܰྔʢ1kbະຬʣ - ෳStore posva / pinia
Store import { defineStore } from "pinia"; export const useCounterStore
= defineStore({ id: "counter", state: () => ({ count: 0 }), actions: { increment() { this.count++; }, decrement() { this.count--; } } });
Store import { defineStore } from "pinia"; export const useCounterStore
= defineStore({ id: "counter", state: () => ({ count: 0 }), actions: { increment() { this.count++; }, decrement() { this.count--; } } }); mutationsͳ͘actionsͰ stateΛૢ࡞ storeݻ༗ͷ idΛ࣋ͭ
Install import { createApp } from "vue"; import App from
"./App.vue"; import { createPinia } from "pinia"; const app = createApp(App); // pinia app.use(createPinia()); app.mount("#app");
Install import { createApp } from "vue"; import App from
"./App.vue"; import { createPinia } from "pinia"; const app = createApp(App); // pinia app.use(createPinia()); app.mount("#app"); piniaͷrootετΞΛొ
Components (read) <script lang="ts"> import { defineComponent, computed } from
"vue"; import { useCounterStore } from "@/stores/pinia/store"; export default defineComponent({ name: "Counter", setup() { const store = useCounterStore(); const count = computed(() => store.count); return { count }; } }); </script>
Components (read) <script lang="ts"> import { defineComponent, computed } from
"vue"; import { useCounterStore } from "@/stores/pinia/store"; export default defineComponent({ name: "Counter", setup() { const store = useCounterStore(); const count = computed(() => store.count); return { count }; } }); </script> numberܕͱͯ͠ਪ exportͨ͠StoreΛར༻
<script lang="ts"> import { defineComponent } from "vue"; import {
useCounterStore } from "@/stores/pinia/store"; export default defineComponent({ name: "IncrementButton", setup() { const store = useCounterStore(); const increment = () => store.increment(); return { increment }; } }); </script> Components (write)
<script lang="ts"> import { defineComponent } from "vue"; import {
useCounterStore } from "@/stores/pinia/store"; export default defineComponent({ name: "IncrementButton", setup() { const store = useCounterStore(); const increment = () => store.increment(); return { increment }; } }); </script> Components (write) actionsͷ ܕิ͕ޮ͘
Demo https://vue-state-management-samples.vercel.app/pinia
- TypeScript શରԠ - DevToolsͷ࿈ܞʢݱঢ়ࢀরͷΈʣ - γϯϓϧͳίʔυ - SSRରԠ Pros
😁
- ใྔͷগͳ͞ - ਖ਼ࣜϦϦʔεલ - ։ൃͷܧଓੑ Cons 😵
Vuex Pinia Composition API Store vue-apollo
- Composition APIͰ ಠ࣮ࣗͨ͠Store Composition Store
Store import { reactive, provide, InjectionKey, toRefs } from "vue";
import { DeepReadonly } from "utility-types"; export const createStore = () => { const state = reactive({ count: 0 }); const actions = { increment: () => { state.count++; }, decrement: () => { state.count--; } }; return { state: toRefs(state), actions }; }; type Store = ReturnType<DeepReadonly<typeof createStore>>; export const STORE_KEY: InjectionKey<Store> = Symbol("Store"); export const useStore = () => { return inject(STORE_KEY) as Store; };
Store import { reactive, provide, InjectionKey, toRefs } from "vue";
import { DeepReadonly } from "utility-types"; export const createStore = () => { const state = reactive({ count: 0 }); const actions = { increment: () => { state.count++; }, decrement: () => { state.count--; } }; return { state: toRefs(state), actions }; }; type Store = ReturnType<DeepReadonly<typeof createStore>>; export const STORE_KEY: InjectionKey<Store> = Symbol("Store"); export const useStore = () => { return inject(STORE_KEY) as Store; }; reactiveͰstateΛఆٛ ؔͰstateΛૢ࡞
Store import { reactive, provide, InjectionKey, toRefs } from "vue";
import { DeepReadonly } from "utility-types"; export const createStore = () => { const state = reactive({ count: 0 }); const actions = { increment: () => { state.count++; }, decrement: () => { state.count--; } }; return { state: toRefs(state), actions }; }; type Store = DeepReadonly<ReturnType<typeof createStore>>; export const STORE_KEY: InjectionKey<Store> = Symbol("Store"); export const useStore = () => { return inject(STORE_KEY) as Store; }; provide/inject༻ͷ ؔɾΩʔ DeepReadolyͰ stateͷॻ͖͑Λېࢭ্ͨ͠Ͱ InjectionKeyͷܕʹઃఆ
Install import { createApp, provide } from "vue"; import App
from "./App.vue"; import { STORE_KEY, createStore } from "@/stores/originalStore/store"; const app = createApp(App); // Original Store app.provide(STORE_KEY, createStore()); app.mount("#app");
import { createApp, provide } from "vue"; import App from
"./App.vue"; import { STORE_KEY, createStore } from "@/stores/originalStore/store"; const app = createApp(App); // Original Store app.provide(STORE_KEY, createStore()); app.mount("#app"); Install Storeͷ࡞ͱprovideͰͷొ
Components (read) <script lang="ts"> import { defineComponent, computed } from
"vue"; import { useStore } from "@/stores/originalStore/store"; export default defineComponent({ name: "Counter", setup() { const { state } = useStore(); const count = computed(() => state.count.value); return { count }; } }); </script>
Components (read) <script lang="ts"> import { defineComponent, computed } from
"vue"; import { useStore } from "@/stores/originalStore/store"; export default defineComponent({ name: "Counter", setup() { const { state } = useStore(); const count = computed(() => state.count.value); return { count }; } }); </script> injectͰͷstoreͷऔಘ numberܕͱͯ͠ਪ
<script lang="ts"> import { defineComponent } from "vue"; import {
useStore } from "@/stores/originalStore/store"; export default defineComponent({ name: "IncrementButton", setup() { const { actions } = useStore(); const increment = () => actions.increment(); return { increment }; } }); </script> Components (write)
<script lang="ts"> import { defineComponent } from "vue"; import {
useStore } from "@/stores/originalStore/store"; export default defineComponent({ name: "IncrementButton", setup() { const { actions } = useStore(); const increment = () => actions.increment(); return { increment }; } }); </script> Components (write) ୯७ͳؔݺͼग़͠ ͳͷͰܕิ͕ޮ͘
Demo https://vue-state-management-samples.vercel.app/original-store
- TypeScript શରԠ - γϯϓϧͳίʔυ - ґଘͳ͠ Pros 😁
- ΦϨΦϨStoreͷ - DevTools ࿈ܞ - vue-routerɺSSRͷରԠ Cons 😵
Vuex Pinia Vue Apollo Composition API Store
- Apollo CacheΛStoreʹ - Query / MutationͰͷૢ࡞ vuejs / vue-apollo
GraphQLͷεΩʔϚఆٛ import gql from "graphql-tag"; export const typeDefs = gql`
extend type Store { count: Int! } extend type Mutation { increment: Int decrement: Int } extend type Query { CountQuery: Store } `;
Queryͷఆٛ import gql from "graphql-tag"; export const COUNT_QUERY = gql`
query CountQuery { store @client { count } } `;
Queryͷఆٛ import gql from "graphql-tag"; export const COUNT_QUERY = gql`
query CountQuery { store @client { count } } `; @clientͱσΟϨΫςΟϒΛ͚ͭΔ͜ͱͰɺ αʔόʔʹ͍߹ΘͤͣɺΩϟογϡͰॲཧ͢Δ
import gql from "graphql-tag"; export const INCREMENT_MUTATION = gql` mutation
incrementMutation { increment @client } `; export const DECREMENT_MUTATION = gql` mutation decrementMutation { decrement @client } `; Mutationͷఆٛ
Resolvers import { InMemoryCache } from "apollo-cache-inmemory"; import { COUNT_QUERY
} from "@/stores/apolloClient/queries"; export const resolvers = { Mutation: { increment: ( _: unknown, _arg: unknown, { cache }: { cache: InMemoryCache }) => { const data = cache.readQuery<any>({ query: COUNT_QUERY }); data.store.count++; cache.writeQuery({ query: COUNT_QUERY, data }); return data.store.count; }, decrement: ( _: unknown, _arg: unknown, { cache }: { cache: InMemoryCache }) => { const data = cache.readQuery<any>({ query: COUNT_QUERY }); data.store.count--; cache.writeQuery({ query: COUNT_QUERY, data }); return data.store.count; } } };
Resolvers import { InMemoryCache } from "apollo-cache-inmemory"; import { COUNT_QUERY
} from "@/stores/apolloClient/queries"; export const resolvers = { Mutation: { increment: ( _: unknown, _arg: unknown, { cache }: { cache: InMemoryCache }) => { const data = cache.readQuery<any>({ query: COUNT_QUERY }); data.store.count++; cache.writeQuery({ query: COUNT_QUERY, data }); return data.store.count; }, decrement: ( _: unknown, _arg: unknown, { cache }: { cache: InMemoryCache }) => { const data = cache.readQuery<any>({ query: COUNT_QUERY }); data.store.count--; cache.writeQuery({ query: COUNT_QUERY, data }); return data.store.count; } } }; queryͷcacheΛॻ͖͍͑ͯΔ
Apollo Clientͷ࡞ import ApolloClient from "apollo-boost"; import { typeDefs }
from "@/stores/apolloClient/typeDefs"; import { InMemoryCache } from "apollo-cache-inmemory"; import { resolvers } from "@/stores/apolloClient/resolvers"; const cache = new InMemoryCache(); export const apolloClient = new ApolloClient({ cache, typeDefs, resolvers }); // storeͷॳظԽ cache.writeData({ data: { store: { __typename: "Store", count: 0 } } });
Apollo Clientͷ࡞ import ApolloClient from "apollo-boost"; import { typeDefs }
from "@/stores/apolloClient/typeDefs"; import { InMemoryCache } from "apollo-cache-inmemory"; import { resolvers } from "@/stores/apolloClient/resolvers"; const cache = new InMemoryCache(); export const apolloClient = new ApolloClient({ cache, typeDefs, resolvers }); // storeͷॳظԽ cache.writeData({ data: { store: { __typename: "Store", count: 0 } } }); cacheͷॳظԽॲཧ
Install import { createApp } from "vue"; import App from
"./App.vue"; import { DefaultApolloClient } from "@vue/apollo-composable"; import { apolloClient } from "@/stores/apolloClient/apolloClient"; const app = createApp(App); // vue-apollo app.provide(DefaultApolloClient, apolloClient); app.mount("#app");
Install import { createApp } from "vue"; import App from
"./App.vue"; import { DefaultApolloClient } from "@vue/apollo-composable"; import { apolloClient } from "@/stores/apolloClient/apolloClient"; const app = createApp(App); // vue-apollo app.provide(DefaultApolloClient, apolloClient); app.mount("#app"); Apollo ClientΛprovide
Components (read) <script lang="ts"> import { defineComponent } from "vue";
import { useQuery, useResult } from "@vue/apollo-composable"; import { COUNT_QUERY } from "@/stores/apolloClient/queries"; export default defineComponent({ name: "Counter", setup() { const { result } = useQuery(COUNT_QUERY); const count = useResult(result, 0, data => data.store.count); return { count }; } }); </script>
Components (read) <script lang="ts"> import { defineComponent } from "vue";
import { useQuery, useResult } from "@vue/apollo-composable"; import { COUNT_QUERY } from "@/stores/apolloClient/queries"; export default defineComponent({ name: "Counter", setup() { const { result } = useQuery(COUNT_QUERY); const count = useResult(result, 0, data => data.store.count); return { count }; } }); </script> GraphQL QueryͰऔಘ
Components (write) <script lang="ts"> import { defineComponent } from "vue";
import { useMutation } from "@vue/apollo-composable"; import { INCREMENT_MUTATION } from "@/stores/apolloClient/mutations"; export default defineComponent({ name: "IncrementButton", setup() { const { mutate: increment } = useMutation(INCREMENT_MUTATION); return { increment }; } }); </script>
<script lang="ts"> import { defineComponent } from "vue"; import {
useMutation } from "@vue/apollo-composable"; import { INCREMENT_MUTATION } from "@/stores/apolloClient/mutations"; export default defineComponent({ name: "IncrementButton", setup() { const { mutate: increment } = useMutation(INCREMENT_MUTATION); return { increment }; } }); </script> Components (write) MutationͰॻ͖͑
Demo https://vue-state-management-samples.vercel.app/vue-apollo
- StoreΛ࣋ͨͳ͍ - DevToolsʢApolloʣରԠ Pros 😁
- Vue ApolloɺGraphQLͷґଘ - ঢ়ଶͷѲ͕ͮ͠Β͍ - ։ൃͷܧଓੑ - ίʔυྔͷ૿Ճ Cons
😵
·ͱΊ
7VFY 1JOJB $PNQPTJUJPO"1* 4UPSF 7VF"QPMMP 4UPSFͷ ୯Ұ ෳ ෳ ʢΩϟγϡʣ
%FW5PPMTରԠ ˓ ˚ º ˚ʢ"QPMMPʣ 5ZQF4DSJQUରԠ ˚ ˓ ˓ ˚ ଟػೳੑ ʢ443FUDʣ ˓ ˚ º º ίʔυͷهड़ྔ ˚ ˓ ˓ º
ࠓͷVueͷঢ়ଶཧVuex͚ͩͰͳ͍ɻ ΞϓϦέʔγϣϯͷنॏࢹ͢Δʹ ߹Θͤͯదͳঢ়ଶཧख๏Λબ ͢Δ͜ͱ͕େ
ࢀߟ • you might not need Vuex: https://speakerdeck.com/ntepluhina/you-might-not-need-vuex • Do
you really need Vuex: https://blog.logrocket.com/do-you-really-need-vuex • ΈΜͳͷVue.js: https://gihyo.jp/book/2021/978-4-297-11902-7 • Pinia vs Vuex: https://www.youtube.com/watch?v=ht_1NR7OFWc • intro to vuex: https://www.vuemastery.com/courses/mastering-vuex/intro-to-vuex/ • Pinia doc: https://pinia.esm.dev/ • Vuex4 doc: https://next.vuex.vuejs.org/
͓·͚ Vuex 5 RFCͷ·ͱΊ 2021/03/14 ࣌ https://github.com/kiaking/rfcs/blob/vuex-5/active-rfcs/0000-vuex-5.md
Storeͷఆٛ Storeͷར༻ Mutationsͷഇࢭ dispatchΛհͣ͞ actionsΛݺΔ ᶃ FluxϥΠΫύλʔϯΛഇࢭ
Optional Store Composition Store ΄΅Composition APIͦͷ·· ᶄ 2छྨͷStoreఆٛํ๏
Store 1 Store 2 ωετ͞ΕͨStoreʢModuleʣ Λഇࢭͯ͠ɺComposition Ͱ Storeͷ૬ޓར༻Λߦ͏ ᶅωετ͞ΕͨStoreΛഇࢭ
Store Component Optional Storeͷ߹ ܕΞϊςʔγϣϯΛ͚ͭΔ ʢComposition StoreͰෆཁʣ ༻࣌ ܕิ͕શʹޮ͘ ᶆ
શͳTypeScriptαϙʔτ