refactor(watchlist): 自选股数据源统一到 Redux

- stockSlice: 新增 loadWatchlistQuotes thunk 加载自选股行情
- useWatchlist: 改用 Redux selector 获取自选股数据
- WatchlistMenu: 使用 Redux 数据源,移除本地状态管理

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
zdl
2025-12-23 20:09:06 +08:00
parent 60aa5c80a5
commit b578504591
3 changed files with 260 additions and 93 deletions

View File

@@ -1,7 +1,7 @@
// src/components/Navbars/components/FeatureMenus/WatchlistMenu.js
// 自选股下拉菜单组件
import React, { memo } from 'react';
import React, { memo, useState } from 'react';
import {
Menu,
MenuButton,
@@ -21,6 +21,7 @@ import { ChevronDownIcon } from '@chakra-ui/icons';
import { FiStar } from 'react-icons/fi';
import { useNavigate } from 'react-router-dom';
import { useWatchlist } from '../../../../hooks/useWatchlist';
import FavoriteButton from '@/components/FavoriteButton';
/**
* 自选股下拉菜单组件
@@ -29,6 +30,7 @@ import { useWatchlist } from '../../../../hooks/useWatchlist';
*/
const WatchlistMenu = memo(() => {
const navigate = useNavigate();
const [removingCode, setRemovingCode] = useState(null);
const {
watchlistQuotes,
watchlistLoading,
@@ -39,6 +41,17 @@ const WatchlistMenu = memo(() => {
handleRemoveFromWatchlist
} = useWatchlist();
// 处理取消关注(带 loading 状态)
const handleUnwatch = async (stockCode) => {
if (removingCode) return;
setRemovingCode(stockCode);
try {
await handleRemoveFromWatchlist(stockCode);
} finally {
setRemovingCode(null);
}
};
const titleColor = useColorModeValue('gray.600', 'gray.300');
const loadingTextColor = useColorModeValue('gray.500', 'gray.300');
const emptyTextColor = useColorModeValue('gray.500', 'gray.300');
@@ -114,21 +127,19 @@ const WatchlistMenu = memo(() => {
(item.current_price || '-')}
</Text>
<Box
as="span"
fontSize="xs"
color="red.500"
cursor="pointer"
px={2}
py={1}
borderRadius="md"
_hover={{ bg: 'red.50' }}
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
handleRemoveFromWatchlist(item.stock_code);
}}
>
取消
<FavoriteButton
isFavorite={true}
isLoading={removingCode === item.stock_code}
onClick={() => handleUnwatch(item.stock_code)}
size="sm"
colorScheme="gold"
showTooltip={true}
/>
</Box>
</HStack>
</HStack>