Skip to content

状態管理

vue-h5-template の状態は 3 つのティアに分割されています。適切なティアを選ぶことで Store を小さく保ち、データフローを予測可能にします。

1. 3 ティアモデル

ティアツールライフタイム永続化
ローカル UI 状態ref / reactiveコンポーネント内なしフォーム入力・ダイアログ開閉
サーバーキャッシュ特性 Composable + refView スコープなし商品リスト・商品詳細
アプリ / セッション状態Pinia Storeアプリセッションあり(AES)Auth Token・ユーザー情報・ロール

経験則:データがただ 1 つの View だけに属するなら Pinia には入れません。

2. Pinia 初期化(@vh5/stores

  • 開発環境localStorage に永続化(デバッグしやすい)
  • 本番環境secure-ls で AES 暗号化 + 圧縮
  • Key 形式:${namespace}-${storeId}(3 アプリ間のキャッシュ衝突を防ぐ)

3. 特性 Store の定義

ts
export const useAuthStore = defineStore("auth", {
  state: (): AuthState => ({ accessToken: "", user: null, roles: [] }),
  getters: {
    isAuthenticated: (s) => !!s.accessToken,
    hasRole: (s) => (role: string) => s.roles.includes(role),
  },
  actions: {
    async login(credentials: Credentials) {
      const session = await AuthService.login(credentials);
      this.$patch({
        accessToken: session.accessToken,
        user: session.user,
        roles: session.user.roles,
      });
    },
    logout() {
      this.$reset();
    },
  },
  persist: { pick: ["accessToken", "user", "roles"] },
});

ガイドライン:

  • Store はサービスを呼び出します@vh5/apifetch を直接呼び出しません。
  • persist.pick で永続化が必要なフィールドのみを選択します。
  • ログアウト時は resetAllStores() ですべての Store をリセットします。

4. アプリ設定 Store

特性横断の設定は @vh5/app-shell/store/app.ts に置きます:

ts
export const useAppStore = defineStore("app", {
  state: () => ({ locale: "ja", theme: "light" as "light" | "dark" }),
  actions: {
    setLocale(locale: SupportedLanguage) {
      this.locale = locale;
    },
    setTheme(theme: "light" | "dark") {
      this.theme = theme;
    },
  },
  persist: true,
});

5. サーバーデータは Composable で、Pinia は使わない

ts
// ✅ 推奨
const { data, error, loading } = useProductDetail(id);

// ❌ アンチパターン
productStore.fetchDetail(id);
const data = computed(() => productStore.detail);

6. 状態のリセット

ts
import { resetAllStores } from "@vh5/stores";

await AuthService.logout();
resetAllStores();
router.replace("/login");

Released under the MIT License.