177 lines
5.3 KiB
JavaScript
177 lines
5.3 KiB
JavaScript
// src/contexts/IndustryContext.js
|
||
// 行业分类数据全局上下文 - 使用API获取 + 缓存机制
|
||
|
||
import React, { createContext, useContext, useState, useEffect, useRef } from 'react';
|
||
import { industryData as staticIndustryData } from '../data/industryData';
|
||
import { industryService } from '../services/industryService';
|
||
import { logger } from '../utils/logger';
|
||
|
||
const IndustryContext = createContext();
|
||
|
||
// 缓存配置
|
||
const CACHE_KEY = 'industry_classifications_cache';
|
||
const CACHE_DURATION = 24 * 60 * 60 * 1000; // 1天(24小时)
|
||
|
||
/**
|
||
* useIndustry Hook
|
||
* 在任何组件中使用行业数据
|
||
*/
|
||
export const useIndustry = () => {
|
||
const context = useContext(IndustryContext);
|
||
if (!context) {
|
||
throw new Error('useIndustry must be used within IndustryProvider');
|
||
}
|
||
return context;
|
||
};
|
||
|
||
/**
|
||
* 从 localStorage 读取缓存
|
||
*/
|
||
const loadFromCache = () => {
|
||
try {
|
||
const cached = localStorage.getItem(CACHE_KEY);
|
||
if (!cached) return null;
|
||
|
||
const { data, timestamp } = JSON.parse(cached);
|
||
const now = Date.now();
|
||
|
||
// 检查缓存是否过期(1天)
|
||
if (now - timestamp > CACHE_DURATION) {
|
||
localStorage.removeItem(CACHE_KEY);
|
||
logger.debug('IndustryContext', '缓存已过期,清除缓存');
|
||
return null;
|
||
}
|
||
|
||
logger.debug('IndustryContext', '从缓存加载行业数据', {
|
||
count: data?.length || 0,
|
||
age: Math.round((now - timestamp) / 1000 / 60) + ' 分钟前'
|
||
});
|
||
return data;
|
||
} catch (error) {
|
||
logger.error('IndustryContext', 'loadFromCache', error);
|
||
return null;
|
||
}
|
||
};
|
||
|
||
/**
|
||
* 保存到 localStorage
|
||
*/
|
||
const saveToCache = (data) => {
|
||
try {
|
||
localStorage.setItem(CACHE_KEY, JSON.stringify({
|
||
data,
|
||
timestamp: Date.now()
|
||
}));
|
||
logger.debug('IndustryContext', '行业数据已缓存', {
|
||
count: data?.length || 0
|
||
});
|
||
} catch (error) {
|
||
logger.error('IndustryContext', 'saveToCache', error);
|
||
}
|
||
};
|
||
|
||
/**
|
||
* IndustryProvider 组件
|
||
* 提供全局行业数据管理 - 使用API获取 + 缓存机制
|
||
*/
|
||
export const IndustryProvider = ({ children }) => {
|
||
const [industryData, setIndustryData] = useState(null);
|
||
const [loading, setLoading] = useState(false);
|
||
const [error, setError] = useState(null);
|
||
const hasLoadedRef = useRef(false);
|
||
const isLoadingRef = useRef(false);
|
||
|
||
/**
|
||
* 加载行业数据
|
||
*/
|
||
const loadIndustryData = async () => {
|
||
// 防止重复加载(处理 StrictMode 双重调用)
|
||
if (hasLoadedRef.current || isLoadingRef.current) {
|
||
logger.debug('IndustryContext', '跳过重复加载', {
|
||
hasLoaded: hasLoadedRef.current,
|
||
isLoading: isLoadingRef.current
|
||
});
|
||
return industryData;
|
||
}
|
||
|
||
try {
|
||
isLoadingRef.current = true;
|
||
setLoading(true);
|
||
setError(null);
|
||
|
||
logger.debug('IndustryContext', '开始加载行业数据');
|
||
|
||
// 1. 先尝试从缓存加载
|
||
const cachedData = loadFromCache();
|
||
if (cachedData && cachedData.length > 0) {
|
||
setIndustryData(cachedData);
|
||
hasLoadedRef.current = true;
|
||
return cachedData;
|
||
}
|
||
|
||
// 2. 缓存不存在或过期,调用 API
|
||
logger.debug('IndustryContext', '缓存无效,调用API获取数据');
|
||
const response = await industryService.getClassifications();
|
||
|
||
if (response.success && response.data && response.data.length > 0) {
|
||
setIndustryData(response.data);
|
||
saveToCache(response.data);
|
||
hasLoadedRef.current = true;
|
||
|
||
logger.debug('IndustryContext', 'API数据加载成功', {
|
||
count: response.data.length
|
||
});
|
||
|
||
return response.data;
|
||
} else {
|
||
throw new Error('API返回数据为空');
|
||
}
|
||
} catch (err) {
|
||
// 3. API 失败,回退到静态数据
|
||
logger.warn('IndustryContext', 'API加载失败,使用静态数据', {
|
||
error: err.message
|
||
});
|
||
|
||
setError(err.message);
|
||
setIndustryData(staticIndustryData);
|
||
hasLoadedRef.current = true;
|
||
|
||
return staticIndustryData;
|
||
} finally {
|
||
setLoading(false);
|
||
isLoadingRef.current = false;
|
||
}
|
||
};
|
||
|
||
/**
|
||
* 刷新行业数据(清除缓存并重新加载)
|
||
*/
|
||
const refreshIndustryData = async () => {
|
||
logger.debug('IndustryContext', '刷新行业数据,清除缓存');
|
||
localStorage.removeItem(CACHE_KEY);
|
||
hasLoadedRef.current = false;
|
||
isLoadingRef.current = false;
|
||
return loadIndustryData();
|
||
};
|
||
|
||
// 组件挂载时自动加载数据
|
||
useEffect(() => {
|
||
loadIndustryData();
|
||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||
}, []);
|
||
|
||
const value = {
|
||
industryData,
|
||
loading,
|
||
error,
|
||
loadIndustryData,
|
||
refreshIndustryData
|
||
};
|
||
|
||
return (
|
||
<IndustryContext.Provider value={value}>
|
||
{children}
|
||
</IndustryContext.Provider>
|
||
);
|
||
};
|