refactor(Company): 提取共享的 useStockSearch Hook
- 新增 useStockSearch.ts:统一股票模糊搜索逻辑 - 支持按代码或名称搜索 - 支持排除指定股票(用于对比场景) - 使用 useMemo 优化性能 - 重构 SearchBar.js:使用共享 Hook,减少 15 行代码 - 重构 CompareStockInput.tsx:使用共享 Hook,减少 20 行代码 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -13,6 +13,7 @@ import {
|
||||
VStack,
|
||||
} from '@chakra-ui/react';
|
||||
import { SearchIcon } from '@chakra-ui/icons';
|
||||
import { useStockSearch } from '../../hooks/useStockSearch';
|
||||
|
||||
/**
|
||||
* 股票搜索栏组件(带模糊搜索下拉)
|
||||
@@ -31,27 +32,18 @@ const SearchBar = ({
|
||||
}) => {
|
||||
// 下拉状态
|
||||
const [showDropdown, setShowDropdown] = useState(false);
|
||||
const [filteredStocks, setFilteredStocks] = useState([]);
|
||||
const containerRef = useRef(null);
|
||||
|
||||
// 从 Redux 获取全部股票列表
|
||||
const allStocks = useSelector(state => state.stock.allStocks);
|
||||
|
||||
// 模糊搜索过滤
|
||||
// 使用共享的搜索 Hook
|
||||
const filteredStocks = useStockSearch(allStocks, inputCode, { limit: 10 });
|
||||
|
||||
// 根据搜索结果更新下拉显示状态
|
||||
useEffect(() => {
|
||||
if (inputCode && inputCode.trim()) {
|
||||
const searchTerm = inputCode.trim().toLowerCase();
|
||||
const filtered = allStocks.filter(stock =>
|
||||
stock.code.toLowerCase().includes(searchTerm) ||
|
||||
stock.name.includes(inputCode.trim())
|
||||
).slice(0, 10); // 限制显示10条
|
||||
setFilteredStocks(filtered);
|
||||
setShowDropdown(filtered.length > 0);
|
||||
} else {
|
||||
setFilteredStocks([]);
|
||||
setShowDropdown(false);
|
||||
}
|
||||
}, [inputCode, allStocks]);
|
||||
setShowDropdown(filteredStocks.length > 0 && !!inputCode?.trim());
|
||||
}, [filteredStocks, inputCode]);
|
||||
|
||||
// 点击外部关闭下拉
|
||||
useEffect(() => {
|
||||
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
} from '@chakra-ui/react';
|
||||
import { SearchIcon } from '@chakra-ui/icons';
|
||||
import { BarChart2 } from 'lucide-react';
|
||||
import { useStockSearch, type Stock } from '../../../hooks/useStockSearch';
|
||||
|
||||
interface CompareStockInputProps {
|
||||
onCompare: (stockCode: string) => void;
|
||||
@@ -25,11 +26,6 @@ interface CompareStockInputProps {
|
||||
currentStockCode?: string;
|
||||
}
|
||||
|
||||
interface Stock {
|
||||
code: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
interface RootState {
|
||||
stock: {
|
||||
allStocks: Stock[];
|
||||
@@ -43,7 +39,6 @@ const CompareStockInput: React.FC<CompareStockInputProps> = ({
|
||||
}) => {
|
||||
const [inputValue, setInputValue] = useState('');
|
||||
const [showDropdown, setShowDropdown] = useState(false);
|
||||
const [filteredStocks, setFilteredStocks] = useState<Stock[]>([]);
|
||||
const [selectedStock, setSelectedStock] = useState<Stock | null>(null);
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
@@ -55,25 +50,16 @@ const CompareStockInput: React.FC<CompareStockInputProps> = ({
|
||||
const goldColor = '#F4D03F';
|
||||
const bgColor = '#1A202C';
|
||||
|
||||
// 模糊搜索过滤
|
||||
// 使用共享的搜索 Hook(排除当前股票)
|
||||
const filteredStocks = useStockSearch(allStocks, inputValue, {
|
||||
excludeCode: currentStockCode,
|
||||
limit: 8,
|
||||
});
|
||||
|
||||
// 根据搜索结果更新下拉显示状态
|
||||
useEffect(() => {
|
||||
if (inputValue && inputValue.trim()) {
|
||||
const searchTerm = inputValue.trim().toLowerCase();
|
||||
const filtered = allStocks
|
||||
.filter(
|
||||
(stock) =>
|
||||
stock.code !== currentStockCode && // 排除当前股票
|
||||
(stock.code.toLowerCase().includes(searchTerm) ||
|
||||
stock.name.includes(inputValue.trim()))
|
||||
)
|
||||
.slice(0, 8); // 限制显示8条
|
||||
setFilteredStocks(filtered);
|
||||
setShowDropdown(filtered.length > 0);
|
||||
} else {
|
||||
setFilteredStocks([]);
|
||||
setShowDropdown(false);
|
||||
}
|
||||
}, [inputValue, allStocks, currentStockCode]);
|
||||
setShowDropdown(filteredStocks.length > 0 && !!inputValue?.trim());
|
||||
}, [filteredStocks, inputValue]);
|
||||
|
||||
// 点击外部关闭下拉
|
||||
useEffect(() => {
|
||||
|
||||
Reference in New Issue
Block a user