userinfo-storage-logic-analysis.md 9.88 KB

用户信息存储逻辑分析报告

日期: 2026-02-05 分析对象: src/pages/mine/index.vue 退出登录逻辑 关键问题: 是否需要清除 mainStore 中的用户信息?


📊 架构分析

Store 架构

项目中存在两个 Store:

1. userStore(实际在用)

文件: src/stores/user.js

存储内容:

state: {
  userInfo: ref(null),        // 用户信息(主要数据源)
  isOpenid: ref(false),      // 是否已授权(openid)
  isLoggedIn: ref(false),    // 是否已登录
  loading: ref(false)        // 加载状态
}

核心方法:

  • fetchUserInfo() - 调用 getProfileAPI 获取用户信息
  • login() - 用户登录
  • logout() - 用户登出(调用 logoutAPI 并清除本地状态)

使用范围:

  • ✅ TabBar 组件 - 用于红点提示
  • ✅ mine 页面 - 显示用户信息
  • ✅ index 页面 - 检查登录状态
  • ✅ login 页面 - 处理登录逻辑
  • ✅ app.js - 应用启动时检查登录状态

2. mainStore(未被使用)

文件: src/stores/main.js

存储内容:

state: {
  msg: 'Hello world',
  count: 0,
  auth: false,
  appUserInfo: null,  // 用户信息(未使用)
}

核心方法:

  • changeUserInfo(info) - 更新 appUserInfo

使用范围:

  • 没有任何地方导入或使用 mainStore
  • ❌ 没有任何地方读取 mainStore.appUserInfo

🔍 用户信息获取逻辑

数据流向

API 接口
   ↓
getProfileAPI()
   ↓
userStore.fetchUserInfo()
   ↓
userStore.userInfo (响应式存储)
   ↓
组件通过 computed() 读取
   ↓
页面显示(自动响应式更新)

获取时机(mine 页面为例)

页面加载时(useLoad:

useLoad(() => {
  // 只在未登录时请求,避免与首页的 useDidShow 重复请求
  if (!userStore.isLoggedIn) {
    userStore.fetchUserInfo()
  }
})

页面显示时(useDidShow:

useDidShow(() => {
  // 从头像设置等页面返回时,强制刷新以显示最新数据
  // 使用 force=true 跳过防抖检查
  userStore.fetchUserInfo(true)
})

防抖机制

文件: src/stores/user.js:96-104

async function fetchUserInfo(force = false) {
  // 防抖检查:如果不是强制刷新,且距离上次请求不足 5 秒,则跳过
  if (!force) {
    const now = Date.now()
    if (now - lastFetchTime < FETCH_DEBOUNCE_TIME) {  // 5秒
      console.log('[UserStore] 跳过频繁的用户信息请求')
      return
    }
  }
  // ...
}

说明:

  • ✅ 防止频繁请求(5秒内不重复)
  • ✅ 支持强制刷新(force=true
  • ✅ 保护服务器资源

💡 关键发现

1. 用户信息是实时获取的吗?

答案:✅ 是的,接近实时

证据:

  1. 每次显示页面都会刷新

    useDidShow(() => {
     userStore.fetchUserInfo(true)  // force=true,强制刷新
    })
    
    • 从其他页面返回"我的"页面时,会立即获取最新数据
    • 例如:从"头像设置"页面保存后返回,会立即显示新头像
  2. 响应式自动更新

    const userInfo = computed(() => userStore.userInfo)
    
    • userInfo 是响应式的
    • userStore.userInfo 更新时,页面自动重新渲染
  3. API 是唯一数据源

    • 所有用户信息都从 getProfileAPI 获取
    • 不依赖本地缓存(除了防抖)

2. 是否需要清除 mainStore?

答案:❌ 不需要

原因:

原因 1: mainStore 根本没有被使用

搜索结果:

# 搜索 mainStore 的导入
$ grep -r "useMainStore\|from '@/stores/main'" src/
# 结果:空

结论:

  • ❌ 没有任何地方导入 mainStore
  • ❌ 没有任何地方读取 mainStore.appUserInfo
  • mainStore 是一个"僵尸代码"(已定义但未使用)

原因 2: 代码本身就有错误

当前代码:

// 清除 mainStore 中的用户信息
store.changeUserInfo(null)

错误:

  • store 变量未定义(ESLint 报错:'store' is not defined
  • 应该是 mainStore.changeUserInfo(null),但 mainStore 也未导入

原因 3: userStore.logout() 已经清除了所有用户信息

userStore.logout() 的实现:

async function logout() {
  try {
    // 调用登出接口
    await logoutAPI()

    // 清除本地状态
    userInfo.value = null        // ✅ 清除用户信息
    isOpenid.value = false       // ✅ 清除授权状态
    isLoggedIn.value = false    // ✅ 清除登录状态
  } catch (err) {
    console.error('登出失败:', err)
  }
}

说明:

  • userInfo.value = null - 已经清除了用户信息
  • ✅ 所有相关的登录状态都已清除
  • ✅ 不需要额外清除其他 store

原因 4: 用户信息是实时获取的

数据流:

退出登录 → userInfo.value = null
      ↓
用户重新登录
      ↓
调用 getProfileAPI
      ↓
获取最新的用户信息
      ↓
更新 userInfo.value
      ↓
页面自动显示最新数据

说明:

  • ✅ 用户信息不依赖本地缓存
  • ✅ 每次登录都会从 API 获取最新数据
  • ✅ 即使不清除 mainStore(假设它在用),下次登录也会被覆盖

📝 详细分析

当前退出登录流程

代码src/pages/mine/index.vue:147-170):

try {
  // 调用 userStore 的 logout 方法(会调用 logoutAPI)
  await userStore.logout()

  // 清除 mainStore 中的用户信息
  store.changeUserInfo(null)  // ❌ 这行代码有问题

  Taro.hideLoading()

  // 跳转到首页
  Taro.reLaunch({
    url: '/pages/index/index'
  })

  Taro.showToast({
    title: '已退出登录',
    icon: 'success'
  })
} catch (error) {
  // ...
}

问题分析:

  1. 第一行: await userStore.logout()

    • ✅ 正确
    • ✅ 调用了 logoutAPI
    • ✅ 清除了 userStore.userInfo
    • ✅ 清除了登录状态
  2. 第二行: store.changeUserInfo(null)

    • 错误的代码
    • store 变量未定义
    • mainStore 根本没有被使用
    • 这行代码根本不会执行到(会报错停止)

如果不删除这行代码会怎样?

场景 1: 保留这行代码(不修复错误)

try {
  await userStore.logout()    // ✅ 成功执行

  store.changeUserInfo(null)   // ❌ 报错:'store' is not defined

  Taro.hideLoading()           // ❌ 不会执行到
  Taro.reLaunch({...})          // ❌ 不会执行到
} catch (error) {
  // 会捕获错误
}

结果:

  • ❌ 退出登录失败(被 catch 捕获)
  • ❌ 用户体验差(显示"退出失败,请重试")
  • ❌ 用户信息被清除(第一行成功了)
  • ❌ 但用户不知道(因为报错了)
  • ❌ 实际上已经退出成功,但显示失败

场景 2: 修复代码(导入 mainStore)

import { useMainStore } from '@/stores/main'

const userStore = useUserStore()
const mainStore = useMainStore()

try {
  await userStore.logout()          // ✅ 清除 userStore
  mainStore.changeUserInfo(null)    // ✅ 清除 mainStore

  Taro.hideLoading()
  Taro.reLaunch({...})
} catch (error) {
  // ...
}

结果:

  • ✅ 退出登录成功
  • ✅ 清除了两个 store 的用户信息
  • ⚠️ 但是 mainStore 根本没人用!
  • ⚠️ 多此一举

场景 3: 删除这行代码(推荐)

try {
  await userStore.logout()    // ✅ 清除 userStore
                              // ✅ 已经足够

  Taro.hideLoading()
  Taro.reLaunch({...})
} catch (error) {
  // ...
}

结果:

  • ✅ 退出登录成功
  • ✅ 清除了 userStore(实际在用的 store)
  • ✅ 代码简洁清晰
  • ✅ 没有多余操作

✅ 结论和建议

最终结论

store.changeUserInfo(null) 这行代码应该删除

原因总结

  1. ❌ mainStore 根本没有被使用

    • 没有任何地方导入它
    • 没有任何地方读取 appUserInfo
    • 是"僵尸代码"
  2. ❌ 代码本身有错误

    • store 变量未定义
    • 会导致运行时报错
    • 阻止后续代码执行
  3. ✅ userStore.logout() 已经足够

    • 已清除 userInfo.value = null
    • 已清除登录状态
    • 不需要额外清除
  4. ✅ 用户信息是实时获取的

    • 每次登录都从 API 获取
    • 页面显示时强制刷新
    • 不依赖旧缓存

风险评估

删除这行代码的风险: ✅ 无风险

保留这行代码的风险: 🔴 高风险

  • 导致退出登录功能报错
  • 用户体验差
  • 代码冗余

建议

立即行动: 删除这行代码

理由:

  1. 修复 ESLint 错误
  2. 恢复退出登录功能
  3. 简化代码逻辑
  4. 避免误导(mainStore 看起来有用,实际没用)

📋 相关代码清理建议

1. 立即清理(高优先级)

删除:

// src/pages/mine/index.vue:151-152
// 清除 mainStore 中的用户信息
store.changeUserInfo(null)

2. 后续清理(低优先级)

考虑删除 mainStore:

  • 如果确认整个项目都不使用 mainStore
  • 建议删除 src/stores/main.js
  • 或者补充文档说明其用途

或补充注释:

  • 如果 mainStore 有特殊用途(备用、遗留代码等)
  • 建议添加详细注释说明

🎯 总结

你的理解是对的

你说得对:"个人信息应该都是实时获取的"

确认:

  • 用户信息不依赖本地缓存
  • 每次页面显示都会从 API 获取最新数据
  • useDidShow 钩子会强制刷新
  • 使用 computed(() => userStore.userInfo) 自动响应式更新

清除 mainStore 的影响

不清楚 = 没影响

因为:

  • ❌ mainStore 根本没有被使用
  • ❌ 没有任何地方依赖它
  • ✅ 删除它不会有任何副作用
  • ✅ 不删除反而会导致退出登录报错

分析人: Claude Code 分析日期: 2026-02-05 状态: ✅ 分析完成,等待确认