hookehuyr

fix: 优化用户信息获取,避免重复请求

性能优化:
- User Store 添加防抖机制(5秒内不重复请求)
- 修复 useShow 为 useDidShow(使用正确的 Taro 生命周期)
- "我的"页面统一使用 userStore.fetchUserInfo()
- 移除本地 userInfo ref 和 fetchUserProfile 函数
- 移除对 mainStore 和 getProfileAPI 的直接依赖

配置优化:
- 添加 @/config 路径别名到 config/index.js

效果:
- 从首页跳转到"我的"页面时,请求次数从 2 次减少到 1 次
- 页面间快速切换不会触发重复请求
- 统一状态管理,代码更简洁

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
......@@ -36,6 +36,7 @@ export default defineConfig(async (merge) => {
"@/api": path.resolve(__dirname, "../src/api"),
"@/stores": path.resolve(__dirname, "../src/stores"),
"@/hooks": path.resolve(__dirname, "../src/hooks"),
"@/config": path.resolve(__dirname, "../src/config"),
},
sourceRoot: 'src',
outputRoot: 'dist',
......
......@@ -164,7 +164,7 @@
<script setup>
import { ref, shallowRef } from 'vue';
import Taro, { useShareAppMessage, useLoad, useShow } from '@tarojs/taro';
import Taro, { useShareAppMessage, useLoad, useDidShow } from '@tarojs/taro';
import { useGo } from '@/hooks/useGo';
import { useListItemClick, ListType } from '@/composables/useListItemClick';
import { getDocumentIcon, getDocumentLabel } from '@/utils/documentIcons';
......@@ -342,7 +342,7 @@ useLoad(() => {
});
// 页面显示时刷新用户信息(更新 TabBar 红点状态)
useShow(() => {
useDidShow(() => {
// 只在已登录状态下刷新
if (userStore.isLoggedIn) {
userStore.fetchUserInfo().catch(err => {
......
......@@ -12,7 +12,7 @@
>
<!-- Avatar -->
<view class="w-[160rpx] h-[160rpx] rounded-full overflow-hidden border-2 border-white shadow-sm shrink-0">
<img class="w-full h-full object-cover" :src="userInfo?.avatar?.src || defaultAvatar" />
<img class="w-full h-full object-cover" :src="userInfo?.avatar_url || defaultAvatar" />
</view>
<!-- Info -->
......@@ -68,62 +68,41 @@
</template>
<script setup>
import { ref } from 'vue'
import { computed } from 'vue'
import { useGo } from '@/hooks/useGo'
import { mainStore } from '@/stores/main'
import { useUserStore } from '@/stores/user'
import IconFont from '@/components/IconFont.vue'
import TabBar from '@/components/TabBar.vue'
import NavHeader from '@/components/NavHeader.vue'
import Taro, { useLoad, useDidShow } from '@tarojs/taro'
import { getProfileAPI } from '@/api/user'
import defaultAvatar from '@/assets/images/icon/avatar.svg'
const go = useGo()
const store = mainStore()
const userStore = useUserStore()
/**
* @description 用户信息(响应式)
* @type {import('vue').Ref<{id?: number, name?: string, avatar_url?: string}|null>}
* @description 用户信息(从 userStore 读取,自动响应变化)
*/
const userInfo = ref(null)
/**
* @description 获取用户个人信息
* @description 进入页面时调用,401 自动跳转登录页(由 request.js 拦截器处理)
* @returns {Promise<void>}
*/
const fetchUserProfile = async () => {
try {
const res = await getProfileAPI()
if (res.code === 1 && res.data?.user) {
// 更新响应式数据
userInfo.value = res.data.user
// 更新全局状态
store.changeUserInfo(res.data.user)
} else {
// 接口返回失败(非 401,因为 401 已被 request.js 拦截器处理)
console.warn('获取用户信息失败:', res.msg)
}
} catch (err) {
console.error('获取用户信息异常:', err)
}
}
const userInfo = computed(() => userStore.userInfo)
/**
* @description 页面加载时获取用户信息(首次进入)
*/
useLoad(() => {
fetchUserProfile()
// 只在未登录时请求,避免与首页的 useDidShow 重复请求
if (!userStore.isLoggedIn) {
userStore.fetchUserInfo()
}
})
/**
* @description 页面显示时刷新用户信息(从其他页面返回时)
* @description 例如:从头像设置页面保存后返回,需要刷新显示新头像
* @description 带防抖机制(5秒内不重复请求)
*/
useDidShow(() => {
fetchUserProfile()
// userStore.fetchUserInfo() 内部有防抖逻辑,不会频繁请求
userStore.fetchUserInfo()
})
const menuItems = [
......
......@@ -26,6 +26,12 @@ export const useUserStore = defineStore('user', () => {
/** 加载状态 */
const loading = ref(false)
/** 上次获取用户信息的时间戳(用于防抖) */
let lastFetchTime = 0
/** 防抖时间间隔(毫秒) */
const FETCH_DEBOUNCE_TIME = 5000
// ========== 方法 ==========
/**
......@@ -79,24 +85,40 @@ export const useUserStore = defineStore('user', () => {
/**
* 获取用户信息
* @description 调用 getProfileAPI 获取用户信息
* @description 调用 getProfileAPI 获取用户信息,带防抖机制(5秒内不重复请求)
* @param {boolean} force - 是否强制刷新(忽略防抖)
* @throws {Error} 获取失败时抛出错误
*
* @example
* await userStore.fetchUserInfo()
* await userStore.fetchUserInfo(true) // 强制刷新
*/
async function fetchUserInfo() {
async function fetchUserInfo(force = false) {
// 防抖检查:如果不是强制刷新,且距离上次请求不足 5 秒,则跳过
if (!force) {
const now = Date.now()
if (now - lastFetchTime < FETCH_DEBOUNCE_TIME) {
console.log('[UserStore] 跳过频繁的用户信息请求')
return
}
}
try {
loading.value = true
const res = await getProfileAPI()
if (res.code === 1) {
userInfo.value = res.data.user
// 更新最后请求时间
lastFetchTime = Date.now()
} else {
throw new Error(res.msg || '获取用户信息失败')
}
} catch (err) {
console.error('获取用户信息失败:', err)
throw err
} finally {
loading.value = false
}
}
......