diff --git a/package.json b/package.json
index ef02004a3fbd4d805fabe4175e67c2c8b3bf2bff..80852685698cd26c431ca0f151348d5d282c8797 100644
--- a/package.json
+++ b/package.json
@@ -25,9 +25,9 @@
     "jszip": "^3.10.0",
     "object-hash": "^3.0.0",
     "perfect-scrollbar": "^1.5.2",
+    "pinia": "^2.0.30",
     "vue": "^3.2.30",
-    "vue-i18n": "^9.2.0-beta.9",
-    "vuex": "^4.0.2"
+    "vue-i18n": "^9.2.0-beta.9"
   },
   "devDependencies": {
     "@babel/core": "^7.17.0",
diff --git a/src/App.vue b/src/App.vue
index 580cf4ebac7880d48cae5caf7b6da11804f2792b..aad2e8755981d5a19b915f12167c7410b419be5c 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -197,7 +197,7 @@ const codeVisible = ref(false)
 function handleAction(actionType: ActionType) {
   switch (actionType) {
     case ActionType.Undo:
-      store.commit(UNDO)
+      store[UNDO]()
       recordEvent('action_undo', {
         event_category: 'action',
         event_label: 'Undo',
@@ -205,7 +205,7 @@ function handleAction(actionType: ActionType) {
       break
 
     case ActionType.Redo:
-      store.commit(REDO)
+      store[REDO]()
       recordEvent('action_redo', {
         event_category: 'action',
         event_label: 'Redo',
diff --git a/src/components/ActionBar.vue b/src/components/ActionBar.vue
index 964910e5a98664dd05f3dfdb0009b5edadce2e80..11acf9f27f91025ee16932243b88d4f2066c251e 100644
--- a/src/components/ActionBar.vue
+++ b/src/components/ActionBar.vue
@@ -32,8 +32,8 @@ const { t } = useI18n()
 
 const store = useStore()
 
-const canUndo = computed(() => store.state.history.past.length > 0)
-const canRedo = computed(() => store.state.history.future.length > 0)
+const canUndo = computed(() => store.history.past.length > 0)
+const canRedo = computed(() => store.history.future.length > 0)
 
 const actions = computed(() => [
   {
diff --git a/src/hooks/useAvatarOption.ts b/src/hooks/useAvatarOption.ts
index b204899428c1b08a9c3b2de86d2870119cc64dc4..e996d59084b62830da76b847da616ec00c296bed 100644
--- a/src/hooks/useAvatarOption.ts
+++ b/src/hooks/useAvatarOption.ts
@@ -7,10 +7,10 @@ import type { AvatarOption } from '@/types'
 export default function useAvatarOption() {
   const store = useStore()
 
-  const avatarOption = computed(() => store.state.history.present)
+  const avatarOption = computed(() => store.history.present)
 
   const setAvatarOption = (newOption: AvatarOption) => {
-    store.commit(SET_AVATAR_OPTION, newOption)
+    store[SET_AVATAR_OPTION](newOption)
   }
 
   return [avatarOption, setAvatarOption] as const
diff --git a/src/hooks/useSider.ts b/src/hooks/useSider.ts
index 6d109484b88bceea5e45c09c0a3e83d6f5dfc89b..4d2ffea050f6f87348cc0d49b64547cb74a6256b 100644
--- a/src/hooks/useSider.ts
+++ b/src/hooks/useSider.ts
@@ -6,14 +6,14 @@ import { SET_SIDER_STATUS } from '@/store/mutation-type'
 export default function useSider() {
   const store = useStore()
 
-  const isCollapsed = computed(() => store.state.isSiderCollapsed)
+  const isCollapsed = computed(() => store.isSiderCollapsed)
 
   const openSider = () => {
-    store.commit(SET_SIDER_STATUS, false)
+    store[SET_SIDER_STATUS](false)
   }
 
   const closeSider = () => {
-    store.commit(SET_SIDER_STATUS, true)
+    store[SET_SIDER_STATUS](true)
   }
 
   return { isCollapsed, openSider, closeSider }
diff --git a/src/main.ts b/src/main.ts
index fc37db90092cb449f13631518bc28ca5229bce02..33a02038b1f831284711b400de48baa09a28886e 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -2,16 +2,15 @@ import 'perfect-scrollbar/css/perfect-scrollbar.css'
 import './styles/reset.css'
 import './styles/global.scss'
 
+import { createPinia } from 'pinia'
 import { createApp } from 'vue'
 
-import store, { storeKey } from '@/store'
-
 import App from './App.vue'
 import i18n from './i18n'
 
 const app = createApp(App)
 
-app.use(store, storeKey)
+app.use(createPinia())
 
 app.use(i18n)
 
diff --git a/src/store/index.ts b/src/store/index.ts
index 9ba799b27c373a7cb8c048f39fe451a86188666f..8fbfc94b4dbb3066de25599871cf26a5ee42689a 100644
--- a/src/store/index.ts
+++ b/src/store/index.ts
@@ -1,5 +1,4 @@
-import { type InjectionKey } from 'vue'
-import { type Store, createStore, useStore as baseUseStore } from 'vuex'
+import { defineStore } from 'pinia'
 
 import { WrapperShape } from '@/enums'
 import type { AvatarOption } from '@/types'
@@ -22,64 +21,53 @@ export interface State {
   isSiderCollapsed: boolean
 }
 
-export default createStore<State>({
-  strict: true,
-
-  state: {
-    history: {
-      past: [],
-      present: getRandomAvatarOption({ wrapperShape: WrapperShape.Squircle }),
-      future: [],
-    },
-    isSiderCollapsed: window.innerWidth <= SCREEN.lg,
-  },
-
-  mutations: {
-    [SET_AVATAR_OPTION](state, data: AvatarOption) {
-      state.history = {
-        past: [...state.history.past, state.history.present],
+export const useStore = defineStore('store', {
+  state: () =>
+    ({
+      history: {
+        past: [],
+        present: getRandomAvatarOption({ wrapperShape: WrapperShape.Squircle }),
+        future: [],
+      },
+      isSiderCollapsed: window.innerWidth <= SCREEN.lg,
+    } as State),
+  actions: {
+    [SET_AVATAR_OPTION](data: AvatarOption) {
+      this.history = {
+        past: [...this.history.past, this.history.present],
         present: data,
         future: [],
       }
     },
 
-    [UNDO](state) {
-      if (state.history.past.length > 0) {
-        const previous = state.history.past[state.history.past.length - 1]
-        const newPast = state.history.past.slice(
-          0,
-          state.history.past.length - 1
-        )
-        state.history = {
+    [UNDO]() {
+      if (this.history.past.length > 0) {
+        const previous = this.history.past[this.history.past.length - 1]
+        const newPast = this.history.past.slice(0, this.history.past.length - 1)
+        this.history = {
           past: newPast,
           present: previous,
-          future: [state.history.present, ...state.history.future],
+          future: [this.history.present, ...this.history.future],
         }
       }
     },
 
-    [REDO](state) {
-      if (state.history.future.length > 0) {
-        const next = state.history.future[0]
-        const newFuture = state.history.future.slice(1)
-        state.history = {
-          past: [...state.history.past, state.history.present],
+    [REDO]() {
+      if (this.history.future.length > 0) {
+        const next = this.history.future[0]
+        const newFuture = this.history.future.slice(1)
+        this.history = {
+          past: [...this.history.past, this.history.present],
           present: next,
           future: newFuture,
         }
       }
     },
 
-    [SET_SIDER_STATUS](state, collapsed) {
-      if (collapsed !== state.isSiderCollapsed) {
-        state.isSiderCollapsed = collapsed
+    [SET_SIDER_STATUS](collapsed: boolean) {
+      if (collapsed !== this.isSiderCollapsed) {
+        this.isSiderCollapsed = collapsed
       }
     },
   },
 })
-
-export const storeKey: InjectionKey<Store<State>> = Symbol()
-
-export function useStore() {
-  return baseUseStore(storeKey)
-}
diff --git a/yarn.lock b/yarn.lock
index 49fdbff9bed1e8d64205c903ff978ffbffa86190..ebcf29a176a3e7381523f9d25eba50590b8f7cb1 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1959,16 +1959,16 @@
     "@vue/compiler-dom" "3.2.30"
     "@vue/shared" "3.2.30"
 
-"@vue/devtools-api@^6.0.0-beta.11":
-  version "6.0.0-beta.19"
-  resolved "https://registry.npmmirror.com/@vue/devtools-api/download/@vue/devtools-api-6.0.0-beta.19.tgz?cache=0&sync_timestamp=1633376469341&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2F%40vue%2Fdevtools-api%2Fdownload%2F%40vue%2Fdevtools-api-6.0.0-beta.19.tgz#f8e88059daa424515992426a0c7ea5cde07e99bf"
-  integrity sha1-+OiAWdqkJFFZkkJqDH6lzeB+mb8=
-
 "@vue/devtools-api@^6.0.0-beta.13":
   version "6.0.0-beta.18"
   resolved "https://registry.yarnpkg.com/@vue/devtools-api/-/devtools-api-6.0.0-beta.18.tgz#84c0aff9289a57294cb97490811f69e8a0a67f8a"
   integrity sha512-56vRhO7nXWWFYTx520BQSDlQH5VYpwy62hFDEqi2yHHEBpEqseOP5WYQusq7BEW3DXSY9E9cfPVR5CFtJbKuMg==
 
+"@vue/devtools-api@^6.4.5":
+  version "6.5.0"
+  resolved "https://registry.npmmirror.com/@vue/devtools-api/-/devtools-api-6.5.0.tgz#98b99425edee70b4c992692628fa1ea2c1e57d07"
+  integrity sha512-o9KfBeaBmCKl10usN4crU53fYtC1r7jJwdGKjPT24t348rHxgfpZ0xL3Xm/gLUYnc0oTp8LAmrxOeLyu6tbk2Q==
+
 "@vue/reactivity-transform@3.2.30":
   version "3.2.30"
   resolved "https://registry.yarnpkg.com/@vue/reactivity-transform/-/reactivity-transform-3.2.30.tgz#2006e9f4645777a481b78ae77fc486159afa8480"
@@ -6161,6 +6161,14 @@ pify@^4.0.0, pify@^4.0.1:
   resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231"
   integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==
 
+pinia@^2.0.30:
+  version "2.0.30"
+  resolved "https://registry.npmmirror.com/pinia/-/pinia-2.0.30.tgz#b18a581dad6821ed5fbebfaf631229480ea9d2d9"
+  integrity sha512-q6DUmxWwe/mQgg+55QQjykpKC+aGeGdaJV3niminl19V08dE+LRTvSEuqi6/NLSGCKHI49KGL6tMNEOssFiMyA==
+  dependencies:
+    "@vue/devtools-api" "^6.4.5"
+    vue-demi "*"
+
 pirates@^4.0.1:
   version "4.0.1"
   resolved "https://registry.nlark.com/pirates/download/pirates-4.0.1.tgz#643a92caf894566f91b2b986d2c66950a8e2fb87"
@@ -8172,6 +8180,11 @@ vscode-vue-languageservice@0.31.2:
     vscode-pug-languageservice "0.31.2"
     vscode-typescript-languageservice "0.31.2"
 
+vue-demi@*:
+  version "0.13.11"
+  resolved "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.13.11.tgz#7d90369bdae8974d87b1973564ad390182410d99"
+  integrity sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==
+
 vue-eslint-parser@^8.0.1:
   version "8.0.1"
   resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-8.0.1.tgz#25e08b20a414551531f3e19f999902e1ecf45f13"
@@ -8214,13 +8227,6 @@ vue@^3.2.30:
     "@vue/server-renderer" "3.2.30"
     "@vue/shared" "3.2.30"
 
-vuex@^4.0.2:
-  version "4.0.2"
-  resolved "https://registry.nlark.com/vuex/download/vuex-4.0.2.tgz?cache=0&sync_timestamp=1623945218026&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fvuex%2Fdownload%2Fvuex-4.0.2.tgz#f896dbd5bf2a0e963f00c67e9b610de749ccacc9"
-  integrity sha1-+Jbb1b8qDpY/AMZ+m2EN50nMrMk=
-  dependencies:
-    "@vue/devtools-api" "^6.0.0-beta.11"
-
 w3c-hr-time@^1.0.2:
   version "1.0.2"
   resolved "https://registry.nlark.com/w3c-hr-time/download/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd"