iT邦幫忙

2025 iThome 鐵人賽

DAY 21
0
Vue.js

打造銷售系統30天修練 - 全集中・Vue之呼吸系列 第 21

Day 21:[Stateの呼吸・貳之型] User State - 管理登入狀態與資料

  • 分享至 

  • xImage
  •  

在上一回的修煉中,我們初探了 Pinia 的核心,學會了使用 stategettersactions 來建立一個管理認證 token 的中央倉庫 (authStore)。這解決了跨元件和路由守衛的狀態共享問題。

但目前為止,我們的應用程式只知道「有沒有人登入」,卻不知道「登入的人是誰」。Header 元件無法顯示使用者名稱,儀表板也無法根據不同的使用者角色顯示對應的功能。顯然,我們的 authStore 還不夠完整。

今天,我們會將 authStore 升級,讓它不只是一個 token 的容器,而是一個能完整管理使用者狀態與資料的中心。

擴充我們的 Auth Store

我們的目標是讓 authStore 也能儲存從後端獲取的使用者個人資料(例如:姓名、Email、角色等)。

讓我們來擴充 src/stores/auth.js

// src/stores/auth.js
import { defineStore } from 'pinia'

export const useAuthStore = defineStore('auth', {
  state: () => ({
    token: localStorage.getItem('pos-auth-token') || null,
    // 新增一個 state 來儲存使用者資訊
    user: null,
  }),

  getters: {
    isLoggedIn: (state) => !!state.token,

    // 新增 getters 來方便地存取使用者資料
    userName: (state) => state.user?.name || '訪客',
    userAvatar: (state) => state.user?.avatar || 'default-avatar.png',
    userRoles: (state) => state.user?.roles || [],
  },

  actions: {
    // ...
  },
})

我們在 state 中新增了 user: null 作為初始值,並在 getters 中新增了 userNameuserAvatar 等。使用 ?. (Optional Chaining) 和 || 可以確保即使 state.usernull,我們的程式碼也不會報錯,而是會有一個降級(fallback)結果(例如顯示「訪客」)。

在登入後取得使用者資料

儲存使用者資料最好的時機,就是在登入成功的那一刻。通常,一個設計良好的後端登入 API,在驗證成功後,會同時回傳 token 和該名使用者的基本資料。

因此,我們需要修改 login action,讓它能接收並儲存這兩份資料。

// src/stores/auth.js actions

// ...
  actions: {
    // 讓 login action 同時接收 token 和 user 物件
    login(token, user) {
      this.token = token;
      this.user = user;
      localStorage.setItem('pos-auth-token', token);
    },

    logout() {
      this.token = null;
      this.user = null;
      localStorage.removeItem('pos-auth-token');
    },
  },
// ...

相對地,在 LoginView.vue 中,當我們呼叫後端 API 並驗證成功後,就應該這樣呼叫 login action:

// LoginView.vue
import { useAuthStore } from '@/stores/auth';

const authStore = useAuthStore();

async function handleBackendVerification() {
  // ...
  const { appToken, userProfile } = await backendResponse.json();

  // 將 token 和 userProfile 一起傳入 action
  authStore.login(appToken, userProfile);

  router.push('/dashboard');
}

處理頁面重新整理:恢復使用者狀態

現在我們遇到了一個 SPA 中非常經典的問題:當使用者在 /dashboard 頁面按下 F5 重新整理時,會發生什麼事?

  1. 整個 Vue 應用重新初始化。
  2. authStore 被重新建立。
  3. state.token 因為我們有 localStorage,所以成功被恢復。
  4. 但是 state.user 變回了初始值 null

這會導致畫面上本來顯示「歡迎,Noopy」的地方,瞬間變回「歡迎,訪客」。這不是我們想要的!

解決方案:在應用程式初始化時,如果發現有 token 存在,就應該主動向後端發起一個請求,來獲取當前登入者的資料。

讓我們在 authStore 中新增一個 fetchUserProfile action:

// src/stores/auth.js actions

// ...
  actions: {
    // ... login, logout

    // 這個 action 用於在應用初始化時恢復使用者狀態
    async fetchUserProfile() {
      // 只有在 token 存在時才執行
      if (this.token) {
        try {
          // 假設我們有一個 API client 和一個 /api/me 的端點
          // const response = await apiClient.get('/me');
          // this.user = response.data;

          // --- 模擬 API 回應 ---
          const mockUser = { name: 'Noopy', email: 'test@example.com', roles: ['admin'] };
          this.user = mockUser;
          // --------------------

        } catch (error) {
          console.error('獲取使用者資料失敗', error);
          // 如果 token 無效或過期,API 可能會回傳 401
          // 此時應該將使用者登出
          this.logout();
        }
      }
    },
  },
// ...

那麼,該在哪裡呼叫這個 fetchUserProfile action 呢?

最佳地點就是我們應用的最頂層元件——App.vue。因為它只會在應用程式第一次載入時被掛載一次。

// src/App.vue
<script setup>
import { onMounted } from 'vue';
import { useAuthStore } from './stores/auth';

const authStore = useAuthStore();

onMounted(() => {
  // 在元件掛載後,嘗試獲取使用者資料
  authStore.fetchUserProfile();
});
</script>

<template>
  <router-view />
</template>

透過這個機制,每次使用者打開或重新整理我們的應用,App.vue 都會確保去檢查並恢復使用者的登入資料,讓我們的 UI 狀態保持一致!

總結

今天,我們的 authStore 真正進化成了名副其實的「使用者狀態」管理者。我們學到了:

  1. 在 Pinia state 中同時儲存 tokenuser 物件。
  2. login action 中一次性地更新所有認證相關狀態。
  3. 最重要的:如何在 App.vueonMounted Hook中呼叫一個 action (fetchUserProfile),來處理頁面重新整理時的狀態恢復問題。

現在,我們的應用程式不僅知道「有沒有人」,還知道「那個人是誰」,並且能在任何時候都記住他。

有了可靠的狀態,下一步,我們就該建立一個可靠的管道來跟後端要資料了。沒錯,

明日,Day 22:[APIの呼吸・壹之型] Backend連接 - Axios設定與封裝


上一篇
Day 20:[Stateの呼吸・壹之型] Pinia入門 - 全域狀態管理
下一篇
Day 22:[APIの呼吸・壹之型] Backend連接 - Axios設定與封裝
系列文
打造銷售系統30天修練 - 全集中・Vue之呼吸22
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言