# 🚨 useShopInfo 无限循环问题修复

## 问题描述

`useShopInfo` Hook 出现无限循环请求的问题，控制台不断输出 `shopInfo` 请求日志。

## 🔍 问题分析

### 根本原因
Hook中存在循环依赖导致的无限循环：

```typescript
// 问题代码 ❌
const fetchShopInfo = useCallback(async (forceRefresh = false) => {
  if (!forceRefresh && loadShopInfoFromStorage()) {
    return shopInfo; // 依赖shopInfo
  }
  // ...
}, [shopInfo, loadShopInfoFromStorage, saveShopInfoToStorage]); // 依赖shopInfo

useEffect(() => {
  fetchShopInfo(); // 依赖fetchShopInfo
}, [fetchShopInfo]); // 当fetchShopInfo变化时重新执行
```

### 循环链路
1. `useEffect` 依赖 `fetchShopInfo`
2. `fetchShopInfo` 依赖 `shopInfo`
3. 当 `shopInfo` 更新时，`fetchShopInfo` 重新创建
4. `fetchShopInfo` 变化触发 `useEffect` 重新执行
5. `useEffect` 再次调用 `fetchShopInfo`
6. 无限循环 🔄

## 🔧 修复方案

### 1. **移除fetchShopInfo对shopInfo的依赖**

#### 修复前 ❌
```typescript
const fetchShopInfo = useCallback(async (forceRefresh = false) => {
  // 如果不是强制刷新，先尝试从缓存加载
  if (!forceRefresh && loadShopInfoFromStorage()) {
    return shopInfo; // ❌ 依赖shopInfo导致循环
  }
  // ...
}, [shopInfo, loadShopInfoFromStorage, saveShopInfoToStorage]);
```

#### 修复后 ✅
```typescript
const fetchShopInfo = useCallback(async (forceRefresh = false) => {
  try {
    setLoading(true);
    setError(null);
    
    const data = await getShopInfo();
    setShopInfo(data);
    
    // 保存到本地存储
    saveShopInfoToStorage(data);
    
    return data;
  } catch (error) {
    // 错误处理...
  } finally {
    setLoading(false);
  }
}, [saveShopInfoToStorage]); // ✅ 移除shopInfo依赖
```

### 2. **重构初始化逻辑**

#### 修复前 ❌
```typescript
useEffect(() => {
  fetchShopInfo(); // ❌ 依赖fetchShopInfo导致循环
}, [fetchShopInfo]);
```

#### 修复后 ✅
```typescript
useEffect(() => {
  const initShopInfo = async () => {
    // 先尝试从缓存加载
    const hasCache = loadShopInfoFromStorage();
    
    // 如果没有缓存，则从服务器获取
    if (!hasCache) {
      await fetchShopInfo();
    }
  };
  
  initShopInfo();
}, []); // ✅ 空依赖数组，只执行一次
```

### 3. **独立的刷新函数**

#### 修复前 ❌
```typescript
const refreshShopInfo = useCallback(() => {
  return fetchShopInfo(true); // ❌ 依赖fetchShopInfo
}, [fetchShopInfo]);
```

#### 修复后 ✅
```typescript
const refreshShopInfo = useCallback(async () => {
  try {
    setLoading(true);
    setError(null);
    
    const data = await getShopInfo();
    setShopInfo(data);
    
    // 保存到本地存储
    saveShopInfoToStorage(data);
    
    return data;
  } catch (error) {
    // 错误处理...
  } finally {
    setLoading(false);
  }
}, [saveShopInfoToStorage]); // ✅ 独立实现，避免循环依赖
```

## 📊 修复对比

| 项目 | 修复前 | 修复后 | 说明 |
|------|--------|--------|------|
| **fetchShopInfo依赖** | `[shopInfo, ...]` | `[saveShopInfoToStorage]` | 移除shopInfo依赖 |
| **useEffect依赖** | `[fetchShopInfo]` | `[]` | 只执行一次初始化 |
| **缓存检查** | 在fetchShopInfo中 | 在useEffect中 | 分离关注点 |
| **刷新函数** | 依赖fetchShopInfo | 独立实现 | 避免循环依赖 |
| **请求次数** | 无限循环 | 按需请求 | 性能优化 |

## ✅ 修复效果

### 修复前 ❌
```
🔄 无限循环请求
📊 控制台不断输出shopInfo日志
⚡ 性能问题，浪费网络资源
🐛 用户体验差，页面卡顿
```

### 修复后 ✅
```
✅ 只在需要时请求一次
📊 控制台日志正常
⚡ 性能优化，智能缓存
🚀 用户体验良好，页面流畅
```

## 🎯 Hook执行流程

### 修复后的正确流程
```
1. 组件挂载
   ↓
2. useEffect执行（只执行一次）
   ↓
3. 检查本地缓存
   ↓
4. 如果有缓存 → 使用缓存数据，结束
   ↓
5. 如果无缓存 → 调用fetchShopInfo
   ↓
6. 获取数据，更新状态，保存缓存
   ↓
7. 结束，不再重复请求
```

## 🧪 验证方法

### 1. **控制台检查**
- ✅ 不再有重复的shopInfo请求日志
- ✅ 只在初始化时请求一次
- ✅ 刷新时才会重新请求

### 2. **网络面板检查**
- ✅ Network面板中只有必要的请求
- ✅ 没有重复的/shop/getShopInfo请求
- ✅ 缓存机制正常工作

### 3. **功能验证**
- ✅ 商店信息正常显示
- ✅ Logo和网站名称正确
- ✅ 缓存机制工作正常
- ✅ 手动刷新功能正常

## 🛠️ 预防措施

### 1. **避免循环依赖**
```typescript
// ❌ 避免这样的依赖关系
const funcA = useCallback(() => {
  // 使用stateB
}, [stateB]);

const funcB = useCallback(() => {
  funcA();
}, [funcA]);

useEffect(() => {
  funcB();
}, [funcB]);
```

### 2. **合理使用useCallback依赖**
```typescript
// ✅ 只依赖真正需要的值
const fetchData = useCallback(async () => {
  // 不要在依赖数组中包含会变化的状态
}, [/* 只包含稳定的依赖 */]);
```

### 3. **useEffect依赖管理**
```typescript
// ✅ 初始化逻辑使用空依赖数组
useEffect(() => {
  // 初始化逻辑
}, []); // 只执行一次

// ✅ 响应式逻辑明确依赖
useEffect(() => {
  // 响应某个值的变化
}, [specificValue]);
```

## 📈 性能改进

### 请求优化
- ✅ **减少网络请求**：从无限循环到按需请求
- ✅ **智能缓存**：30分钟缓存机制正常工作
- ✅ **内存优化**：避免不必要的重渲染

### 用户体验
- ✅ **页面流畅**：消除卡顿问题
- ✅ **快速加载**：缓存数据立即可用
- ✅ **错误处理**：网络失败时使用缓存

## 🎉 总结

通过重构Hook的依赖关系和执行流程，成功修复了无限循环问题：

- ✅ **移除循环依赖**：fetchShopInfo不再依赖shopInfo
- ✅ **优化初始化**：useEffect只执行一次
- ✅ **独立刷新函数**：避免函数间的循环依赖
- ✅ **保持功能完整**：所有原有功能正常工作
- ✅ **性能提升**：从无限请求到智能缓存

**现在useShopInfo Hook工作正常，不再有无限循环问题！** 🚀
