@@ -1,197 +1,431 @@
// HeroPanel - DetailModal 状态管理 Hook
// 整合 DetailModal 组件的所有状态,使主组件更简洁
// 使用 useReducer 优化,减少不必要的重渲染
import { useState , useCallback } from "react" ;
import { useReducer , useCallback , useMemo , useRef } from "react" ;
// ========== 初始状态 ==========
const initialState = {
// UI 状态
ztViewMode : "sector" , // 'sector' | 'stock'
selectedSectorFilter : null ,
expandedReasons : { } ,
// 弹窗/抽屉状态
detailDrawerVisible : false ,
selectedContent : null ,
sectorStocksModalVisible : false ,
selectedSectorInfo : null ,
stocksDrawerVisible : false ,
selectedEventStocks : [ ] ,
selectedEventTime : null ,
selectedEventTitle : "" ,
klineModalVisible : false ,
selectedKlineStock : null ,
relatedEventsModalVisible : false ,
selectedRelatedEvents : { sectorName : "" , events : [ ] } ,
// 数据加载状态
stockQuotes : { } ,
stockQuotesLoading : false ,
} ;
// ========== Action Types ==========
const ActionTypes = {
SET _ZT _VIEW _MODE : "SET_ZT_VIEW_MODE" ,
SET _SECTOR _FILTER : "SET_SECTOR_FILTER" ,
TOGGLE _EXPANDED _REASON : "TOGGLE_EXPANDED_REASON" ,
SET _EXPANDED _REASONS : "SET_EXPANDED_REASONS" ,
OPEN _CONTENT _DETAIL : "OPEN_CONTENT_DETAIL" ,
CLOSE _CONTENT _DETAIL : "CLOSE_CONTENT_DETAIL" ,
OPEN _SECTOR _STOCKS : "OPEN_SECTOR_STOCKS" ,
CLOSE _SECTOR _STOCKS : "CLOSE_SECTOR_STOCKS" ,
OPEN _EVENT _STOCKS : "OPEN_EVENT_STOCKS" ,
CLOSE _EVENT _STOCKS : "CLOSE_EVENT_STOCKS" ,
OPEN _KLINE _MODAL : "OPEN_KLINE_MODAL" ,
CLOSE _KLINE _MODAL : "CLOSE_KLINE_MODAL" ,
OPEN _RELATED _EVENTS : "OPEN_RELATED_EVENTS" ,
CLOSE _RELATED _EVENTS : "CLOSE_RELATED_EVENTS" ,
SET _STOCK _QUOTES : "SET_STOCK_QUOTES" ,
SET _STOCK _QUOTES _LOADING : "SET_STOCK_QUOTES_LOADING" ,
RESET _ALL : "RESET_ALL" ,
} ;
// ========== Reducer ==========
function reducer ( state , action ) {
switch ( action . type ) {
case ActionTypes . SET _ZT _VIEW _MODE :
return { ... state , ztViewMode : action . payload } ;
case ActionTypes . SET _SECTOR _FILTER :
return { ... state , selectedSectorFilter : action . payload } ;
case ActionTypes . TOGGLE _EXPANDED _REASON :
return {
... state ,
expandedReasons : {
... state . expandedReasons ,
[ action . payload ] : ! state . expandedReasons [ action . payload ] ,
} ,
} ;
case ActionTypes . SET _EXPANDED _REASONS :
return { ... state , expandedReasons : action . payload } ;
case ActionTypes . OPEN _CONTENT _DETAIL :
return {
... state ,
selectedContent : action . payload ,
detailDrawerVisible : true ,
} ;
case ActionTypes . CLOSE _CONTENT _DETAIL :
return {
... state ,
detailDrawerVisible : false ,
selectedContent : null ,
} ;
case ActionTypes . OPEN _SECTOR _STOCKS :
return {
... state ,
selectedSectorInfo : action . payload ,
sectorStocksModalVisible : true ,
} ;
case ActionTypes . CLOSE _SECTOR _STOCKS :
return {
... state ,
sectorStocksModalVisible : false ,
selectedSectorInfo : null ,
} ;
case ActionTypes . OPEN _EVENT _STOCKS :
return {
... state ,
selectedEventStocks : action . payload . stocks ,
selectedEventTime : action . payload . time ,
selectedEventTitle : action . payload . title ,
stocksDrawerVisible : true ,
} ;
case ActionTypes . CLOSE _EVENT _STOCKS :
return {
... state ,
stocksDrawerVisible : false ,
selectedEventStocks : [ ] ,
selectedEventTime : null ,
selectedEventTitle : "" ,
} ;
case ActionTypes . OPEN _KLINE _MODAL :
return {
... state ,
selectedKlineStock : action . payload ,
klineModalVisible : true ,
} ;
case ActionTypes . CLOSE _KLINE _MODAL :
return {
... state ,
klineModalVisible : false ,
selectedKlineStock : null ,
} ;
case ActionTypes . OPEN _RELATED _EVENTS :
return {
... state ,
selectedRelatedEvents : action . payload ,
relatedEventsModalVisible : true ,
} ;
case ActionTypes . CLOSE _RELATED _EVENTS :
return {
... state ,
relatedEventsModalVisible : false ,
selectedRelatedEvents : { sectorName : "" , events : [ ] } ,
} ;
case ActionTypes . SET _STOCK _QUOTES :
return { ... state , stockQuotes : action . payload } ;
case ActionTypes . SET _STOCK _QUOTES _LOADING :
return { ... state , stockQuotesLoading : action . payload } ;
case ActionTypes . RESET _ALL :
return initialState ;
default :
return state ;
}
}
/**
* DetailModal 状态管理 Hook
* 将 17 个 useState 整合为一个自定义 hook
* DetailModal 状态管理 Hook (useReducer 优化版)
* 将 17 个 useState 整合为单个 useReducer, 减少重渲染
*/
export const useDetailModalState = ( ) => {
// ========== UI 状态 ==========
// 视图模式:板块视图 | 个股视图
const [ ztViewMode , setZtViewMode ] = useState ( "sector" ) ; // 'sector' | 'stock'
// 板块筛选(个股视图时使用)
const [ selectedSectorFilter , setSelectedSectorFilter ] = useState ( null ) ;
// 展开的涨停原因
const [ expandedReasons , setExpandedReasons ] = useState ( { } ) ;
const [ state , dispatch ] = useReducer ( reducer , initialState ) ;
// ========== 弹窗/抽屉状态 ==========
// 内容详情抽屉
const [ detailDrawerVisible , setDetailDrawerVisible ] = useState ( false ) ;
const [ selectedContent , setSelectedContent ] = useState ( null ) ;
// 板块股票弹窗
const [ sectorStocksModalVisible , setSectorStocksModalVisible ] = useState ( false ) ;
const [ selectedSectorInfo , setSelectedSectorInfo ] = useState ( null ) ;
// 事件关联股票抽屉
const [ stocksDrawerVisible , setStocksDrawerVisible ] = useState ( false ) ;
const [ selectedEventStocks , setSelectedEventStocks ] = useState ( [ ] ) ;
const [ selectedEventTime , setSelectedEventTime ] = useState ( null ) ;
const [ selectedEventTitle , setSelectedEventTitle ] = useState ( "" ) ;
// K线弹窗
const [ klineModalVisible , setKlineModalVisible ] = useState ( false ) ;
const [ selectedKlineStock , setSelectedKlineStock ] = useState ( null ) ;
// 关联事件弹窗
const [ relatedEventsModalVisible , setRelatedEventsModalVisible ] = useState ( false ) ;
const [ selectedRelatedEvents , setSelectedRelatedEvents ] = useState ( {
sectorName : "" ,
events : [ ] ,
} ) ;
// ========== 操作方法(稳定引用) ==========
// ========== 数据加载状态 ==========
const [ stockQuotes , setStockQuotes ] = useState ( { } ) ;
const [ stockQuotesLoading , setStockQuotesLoading ] = useState ( false ) ;
// ========== 操作方法 ==========
// 打开内容详情
const openContentDetail = useCallback ( ( content ) => {
setSelectedContent ( content ) ;
setDetailDrawerVisible ( true ) ;
const setZtViewMode = useCallback ( ( mode ) => {
dispatch ( { type : ActionTypes . SET _ZT _VIEW _MODE , payload : mode } ) ;
} , [ ] ) ;
// 关闭内容详情
const closeContentDetail = useCallback ( ( ) => {
setDetailDrawerVisible ( false ) ;
setSelectedContent ( null ) ;
const setSelectedSectorFilter = useCallback ( ( filter ) => {
dispatch ( { type : ActionTypes . SET _SECTOR _FILTER , payload : filter } ) ;
} , [ ] ) ;
// 打开板块股票弹窗
const openSectorStocks = useCallback ( ( sectorInfo ) => {
setSelectedSectorInfo ( sectorInfo ) ;
setSectorStocksModalVisible ( true ) ;
const setExpandedReasons = useCallback ( ( reasons ) => {
dispatch ( { type : ActionTypes . SET _EXPANDED _REASONS , payload : reasons } ) ;
} , [ ] ) ;
// 关闭板块股票弹窗
const closeSectorStocks = useCallback ( ( ) => {
setSectorStocksModalVisible ( false ) ;
setSelectedSectorInfo ( null ) ;
} , [ ] ) ;
// 打开事件关联股票
const openEventStocks = useCallback ( ( stocks , time , title ) => {
setSelectedEventStocks ( stocks ) ;
setSelectedEventTime ( time ) ;
setSelectedEventTitle ( title ) ;
setStocksDrawerVisible ( true ) ;
} , [ ] ) ;
// 关闭事件关联股票
const closeEventStocks = useCallback ( ( ) => {
setStocksDrawerVisible ( false ) ;
setSelectedEventStocks ( [ ] ) ;
setSelectedEventTime ( null ) ;
setSelectedEventTitle ( "" ) ;
} , [ ] ) ;
// 打开 K 线弹窗
const openKlineModal = useCallback ( ( stock ) => {
setSelectedKlineStock ( stock ) ;
setKlineModalVisible ( true ) ;
} , [ ] ) ;
// 关闭 K 线弹窗
const closeKlineModal = useCallback ( ( ) => {
setKlineModalVisible ( false ) ;
setSelectedKlineStock ( null ) ;
} , [ ] ) ;
// 打开关联事件弹窗
const openRelatedEvents = useCallback ( ( sectorName , events ) => {
setSelectedRelatedEvents ( { sectorName , events } ) ;
setRelatedEventsModalVisible ( true ) ;
} , [ ] ) ;
// 关闭关联事件弹窗
const closeRelatedEvents = useCallback ( ( ) => {
setRelatedEventsModalVisible ( false ) ;
setSelectedRelatedEvents ( { sectorName : "" , events : [ ] } ) ;
} , [ ] ) ;
// 切换展开原因
const toggleExpandedReason = useCallback ( ( stockCode ) => {
setExpandedReasons ( ( prev ) => ( {
... prev ,
[ stockCode ] : ! prev [ stockCode ] ,
} ) ) ;
dispatch ( { type : ActionTypes . TOGGLE _EXPANDED _REASON , payload : stockCode } ) ;
} , [ ] ) ;
const openContentDetail = useCallback ( ( content ) => {
dispatch ( { type : ActionTypes . OPEN _CONTENT _DETAIL , payload : content } ) ;
} , [ ] ) ;
const closeContentDetail = useCallback ( ( ) => {
dispatch ( { type : ActionTypes . CLOSE _CONTENT _DETAIL } ) ;
} , [ ] ) ;
// 兼容旧 API: setDetailDrawerVisible
const setDetailDrawerVisible = useCallback ( ( visible ) => {
if ( visible ) {
// 如果要显示,但没有内容,不做任何事
} else {
dispatch ( { type : ActionTypes . CLOSE _CONTENT _DETAIL } ) ;
}
} , [ ] ) ;
// 兼容旧 API: setSelectedContent
const setSelectedContent = useCallback ( ( content ) => {
if ( content ) {
dispatch ( { type : ActionTypes . OPEN _CONTENT _DETAIL , payload : content } ) ;
}
} , [ ] ) ;
const openSectorStocks = useCallback ( ( sectorInfo ) => {
dispatch ( { type : ActionTypes . OPEN _SECTOR _STOCKS , payload : sectorInfo } ) ;
} , [ ] ) ;
const closeSectorStocks = useCallback ( ( ) => {
dispatch ( { type : ActionTypes . CLOSE _SECTOR _STOCKS } ) ;
} , [ ] ) ;
// 兼容旧 API
const setSectorStocksModalVisible = useCallback ( ( visible ) => {
if ( ! visible ) {
dispatch ( { type : ActionTypes . CLOSE _SECTOR _STOCKS } ) ;
}
} , [ ] ) ;
const setSelectedSectorInfo = useCallback ( ( info ) => {
if ( info ) {
dispatch ( { type : ActionTypes . OPEN _SECTOR _STOCKS , payload : info } ) ;
}
} , [ ] ) ;
const openEventStocks = useCallback ( ( stocks , time , title ) => {
dispatch ( {
type : ActionTypes . OPEN _EVENT _STOCKS ,
payload : { stocks , time , title } ,
} ) ;
} , [ ] ) ;
const closeEventStocks = useCallback ( ( ) => {
dispatch ( { type : ActionTypes . CLOSE _EVENT _STOCKS } ) ;
} , [ ] ) ;
// 兼容旧 API - 支持单独设置股票数据
// 注意:这些 setter 需要配合 setStocksDrawerVisible(true) 使用
const pendingEventStocksRef = useRef ( { stocks : null , time : null , title : null } ) ;
const setStocksDrawerVisible = useCallback ( ( visible ) => {
if ( visible ) {
// 打开时,使用暂存的数据
dispatch ( {
type : ActionTypes . OPEN _EVENT _STOCKS ,
payload : {
stocks : pendingEventStocksRef . current . stocks || [ ] ,
time : pendingEventStocksRef . current . time ,
title : pendingEventStocksRef . current . title || "" ,
} ,
} ) ;
} else {
dispatch ( { type : ActionTypes . CLOSE _EVENT _STOCKS } ) ;
}
} , [ ] ) ;
const setSelectedEventStocks = useCallback ( ( stocks ) => {
pendingEventStocksRef . current . stocks = stocks ;
} , [ ] ) ;
const setSelectedEventTime = useCallback ( ( time ) => {
pendingEventStocksRef . current . time = time ;
} , [ ] ) ;
const setSelectedEventTitle = useCallback ( ( title ) => {
pendingEventStocksRef . current . title = title ;
} , [ ] ) ;
const openKlineModal = useCallback ( ( stock ) => {
dispatch ( { type : ActionTypes . OPEN _KLINE _MODAL , payload : stock } ) ;
} , [ ] ) ;
const closeKlineModal = useCallback ( ( ) => {
dispatch ( { type : ActionTypes . CLOSE _KLINE _MODAL } ) ;
} , [ ] ) ;
// 兼容旧 API
const setKlineModalVisible = useCallback ( ( visible ) => {
if ( ! visible ) {
dispatch ( { type : ActionTypes . CLOSE _KLINE _MODAL } ) ;
}
} , [ ] ) ;
const setSelectedKlineStock = useCallback ( ( stock ) => {
if ( stock ) {
dispatch ( { type : ActionTypes . OPEN _KLINE _MODAL , payload : stock } ) ;
}
} , [ ] ) ;
const openRelatedEvents = useCallback ( ( sectorName , events ) => {
dispatch ( {
type : ActionTypes . OPEN _RELATED _EVENTS ,
payload : { sectorName , events } ,
} ) ;
} , [ ] ) ;
const closeRelatedEvents = useCallback ( ( ) => {
dispatch ( { type : ActionTypes . CLOSE _RELATED _EVENTS } ) ;
} , [ ] ) ;
// 兼容旧 API
const setRelatedEventsModalVisible = useCallback ( ( visible ) => {
if ( ! visible ) {
dispatch ( { type : ActionTypes . CLOSE _RELATED _EVENTS } ) ;
}
} , [ ] ) ;
const setSelectedRelatedEvents = useCallback ( ( data ) => {
if ( data && data . sectorName ) {
dispatch ( { type : ActionTypes . OPEN _RELATED _EVENTS , payload : data } ) ;
}
} , [ ] ) ;
const setStockQuotes = useCallback ( ( quotes ) => {
dispatch ( { type : ActionTypes . SET _STOCK _QUOTES , payload : quotes } ) ;
} , [ ] ) ;
const setStockQuotesLoading = useCallback ( ( loading ) => {
dispatch ( { type : ActionTypes . SET _STOCK _QUOTES _LOADING , payload : loading } ) ;
} , [ ] ) ;
// 重置所有状态(用于关闭弹窗时)
const resetAllState = useCallback ( ( ) => {
setZtViewMode ( "sector" ) ;
setSelectedSectorFilter ( null ) ;
setExpandedReasons ( { } ) ;
setDetailDrawerVisible ( false ) ;
setSelectedContent ( null ) ;
setSectorStocksModalVisible ( false ) ;
setSelectedSectorInfo ( null ) ;
setStocksDrawerVisible ( false ) ;
setSelectedEventStocks ( [ ] ) ;
setSelectedEventTime ( null ) ;
setSelectedEventTitle ( "" ) ;
setKlineModalVisible ( false ) ;
setSelectedKlineStock ( null ) ;
setRelatedEventsModalVisible ( false ) ;
setSelectedRelatedEvents ( { sectorName : "" , events : [ ] } ) ;
setStockQuotes ( { } ) ;
setStockQuotesLoading ( false ) ;
dispatch ( { type : ActionTypes . RESET _ALL } ) ;
} , [ ] ) ;
return {
// UI 状态 + setters
ztViewMode ,
setZtViewMode ,
selectedSectorFilter ,
setSelectedSectorFilter ,
expandedReasons ,
setExpandedReasons ,
// ========== 返回值(保持兼容性) ==========
return useMemo (
( ) => ( {
// UI 状态 + setters
ztViewMode : state . ztViewMode ,
setZtViewMode ,
selectedSectorFilter : state . selectedSectorFilter ,
setSelectedSectorFilter ,
expandedReasons : state . expandedReasons ,
setExpandedReasons ,
// 弹窗状态 + setters
detailDrawerVisible ,
setDetailDrawerVisible ,
selectedContent ,
setSelectedContent ,
sectorStocksModalVisible ,
setSectorStocksModalVisible ,
selectedSectorInfo ,
setSelectedSectorInfo ,
stocksDrawerVisible ,
setStocksDrawerVisible ,
selectedEventStocks ,
setSelectedEventStocks ,
selectedEventTime ,
setSelectedEventTime ,
selectedEventTitle ,
setSelectedEventTitle ,
klineModalVisible ,
setKlineModalVisible ,
selectedKlineStock ,
setSelectedKlineStock ,
relatedEventsModalVisible ,
setRelatedEventsModalVisible ,
selectedRelatedEvents ,
setSelectedRelatedEvents ,
// 弹窗状态 + setters
detailDrawerVisible : state . detailDrawerVisible ,
setDetailDrawerVisible ,
selectedContent : state . selectedContent ,
setSelectedContent ,
sectorStocksModalVisible : state . sectorStocksModalVisible ,
setSectorStocksModalVisible ,
selectedSectorInfo : state . selectedSectorInfo ,
setSelectedSectorInfo ,
stocksDrawerVisible : state . stocksDrawerVisible ,
setStocksDrawerVisible ,
selectedEventStocks : state . selectedEventStocks ,
setSelectedEventStocks ,
selectedEventTime : state . selectedEventTime ,
setSelectedEventTime ,
selectedEventTitle : state . selectedEventTitle ,
setSelectedEventTitle ,
klineModalVisible : state . klineModalVisible ,
setKlineModalVisible ,
selectedKlineStock : state . selectedKlineStock ,
setSelectedKlineStock ,
relatedEventsModalVisible : state . relatedEventsModalVisible ,
setRelatedEventsModalVisible ,
selectedRelatedEvents : state . selectedRelatedEvents ,
setSelectedRelatedEvents ,
// 数据状态 + setters
stockQuotes ,
setStockQuotes ,
stockQuotesLoading ,
setStockQuotesLoading ,
// 数据状态 + setters
stockQuotes : state . stockQuotes ,
setStockQuotes ,
stockQuotesLoading : state . stockQuotesLoading ,
setStockQuotesLoading ,
// 操作方法(高级封装)
openContentDetail ,
closeContentDetail ,
openSectorStocks ,
closeSectorStocks ,
openEventStocks ,
closeEventStocks ,
openKlineModal ,
closeKlineModal ,
openRelatedEvents ,
closeRelatedEvents ,
toggleExpandedReason ,
resetAllState ,
} ;
// 操作方法(高级封装)
openContentDetail ,
closeContentDetail ,
openSectorStocks ,
closeSectorStocks ,
openEventStocks ,
closeEventStocks ,
openKlineModal ,
closeKlineModal ,
openRelatedEvents ,
closeRelatedEvents ,
toggleExpandedReason ,
resetAllState ,
} ) ,
[
state ,
setZtViewMode ,
setSelectedSectorFilter ,
setExpandedReasons ,
setDetailDrawerVisible ,
setSelectedContent ,
setSectorStocksModalVisible ,
setSelectedSectorInfo ,
setStocksDrawerVisible ,
setSelectedEventStocks ,
setSelectedEventTime ,
setSelectedEventTitle ,
setKlineModalVisible ,
setSelectedKlineStock ,
setRelatedEventsModalVisible ,
setSelectedRelatedEvents ,
setStockQuotes ,
setStockQuotesLoading ,
openContentDetail ,
closeContentDetail ,
openSectorStocks ,
closeSectorStocks ,
openEventStocks ,
closeEventStocks ,
openKlineModal ,
closeKlineModal ,
openRelatedEvents ,
closeRelatedEvents ,
toggleExpandedReason ,
resetAllState ,
]
) ;
} ;
export default useDetailModalState ;