From 50a9cdb073151512273550b5585c213ad5abaeef Mon Sep 17 00:00:00 2001 From: tomato6966 Date: Sun, 22 Dec 2024 00:58:20 +0100 Subject: [PATCH] added debouncing --- package-lock.json | 13 +++++++++++++ package.json | 1 + src/App.tsx | 2 +- src/components/AddAssetModal.tsx | 25 ++++--------------------- src/components/PortfolioChart.tsx | 28 +++++++++++++++++++++++++--- 5 files changed, 44 insertions(+), 25 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8bc3036..a249d84 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "react": "^18.3.1", "react-dom": "^18.3.1", "recharts": "^2.12.1", + "use-debounce": "^10.0.4", "zustand": "^4.5.1" }, "devDependencies": { @@ -4172,6 +4173,18 @@ "punycode": "^2.1.0" } }, + "node_modules/use-debounce": { + "version": "10.0.4", + "resolved": "https://registry.npmjs.org/use-debounce/-/use-debounce-10.0.4.tgz", + "integrity": "sha512-6Cf7Yr7Wk7Kdv77nnJMf6de4HuDE4dTxKij+RqE9rufDsI6zsbjyAxcH5y2ueJCQAnfgKbzXbZHYlkFwmBlWkw==", + "license": "MIT", + "engines": { + "node": ">= 16.0.0" + }, + "peerDependencies": { + "react": "*" + } + }, "node_modules/use-sync-external-store": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz", diff --git a/package.json b/package.json index f6ecd87..27e6453 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "react": "^18.3.1", "react-dom": "^18.3.1", "recharts": "^2.12.1", + "use-debounce": "^10.0.4", "zustand": "^4.5.1" }, "devDependencies": { diff --git a/src/App.tsx b/src/App.tsx index 6a2694d..c5389cb 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -41,7 +41,7 @@ export default function App() {
- +
diff --git a/src/components/AddAssetModal.tsx b/src/components/AddAssetModal.tsx index eb46ebe..5850386 100644 --- a/src/components/AddAssetModal.tsx +++ b/src/components/AddAssetModal.tsx @@ -1,5 +1,6 @@ import { Search, X } from "lucide-react"; -import React, { useCallback, useEffect, useRef, useState } from "react"; +import React, { useState } from "react"; +import { useDebouncedCallback } from "use-debounce"; import { getHistoricalData, searchAssets } from "../services/yahooFinanceService"; import { usePortfolioStore } from "../store/portfolioStore"; @@ -13,26 +14,6 @@ export const AddAssetModal = ({ onClose }: { onClose: () => void }) => { addAsset: state.addAsset, dateRange: state.dateRange, })); - const searchTimeoutRef = useRef(); - - const debouncedSearch = useCallback((query: string) => { - if (searchTimeoutRef.current) { - clearTimeout(searchTimeoutRef.current); - } - - searchTimeoutRef.current = setTimeout(() => { - handleSearch(query); - }, 500); - }, []); - - // Cleanup timeout on unmount - useEffect(() => { - return () => { - if (searchTimeoutRef.current) { - clearTimeout(searchTimeoutRef.current); - } - }; - }, []); const handleSearch = async (query: string) => { if (query.length < 2) return; @@ -47,6 +28,8 @@ export const AddAssetModal = ({ onClose }: { onClose: () => void }) => { } }; + const debouncedSearch = useDebouncedCallback(handleSearch, 750); + const handleAssetSelect = async (asset: Asset) => { setLoading(true); try { diff --git a/src/components/PortfolioChart.tsx b/src/components/PortfolioChart.tsx index 50c7817..5d8eb2a 100644 --- a/src/components/PortfolioChart.tsx +++ b/src/components/PortfolioChart.tsx @@ -4,9 +4,12 @@ import { useCallback, useMemo, useState } from "react"; import { CartesianGrid, Legend, Line, LineChart, ResponsiveContainer, Tooltip, XAxis, YAxis } from "recharts"; +import { useDebouncedCallback } from "use-debounce"; import { useDarkMode } from "../providers/DarkModeProvider"; +import { getHistoricalData } from "../services/yahooFinanceService"; import { usePortfolioStore } from "../store/portfolioStore"; +import { DateRange } from "../types"; import { calculatePortfolioValue } from "../utils/calculations/portfolioValue"; import { DateRangePicker } from "./DateRangePicker"; @@ -45,12 +48,25 @@ export const PortfolioChart = () => { const [hideAssets, setHideAssets] = useState(false); const [hiddenAssets, setHiddenAssets] = useState>(new Set()); const { isDarkMode } = useDarkMode(); - const { assets, dateRange, updateDateRange } = usePortfolioStore((state) => ({ + const { assets, dateRange, updateDateRange, updateAssetHistoricalData } = usePortfolioStore((state) => ({ assets: state.assets, dateRange: state.dateRange, updateDateRange: state.updateDateRange, + updateAssetHistoricalData: state.updateAssetHistoricalData, })); + const fetchHistoricalData = useCallback( + async (startDate: string, endDate: string) => { + assets.forEach(async (asset) => { + const historicalData = await getHistoricalData(asset.symbol, startDate, endDate); + updateAssetHistoricalData(asset.id, historicalData); + }); + }, [assets, updateAssetHistoricalData]); + + const debouncedFetchHistoricalData = useDebouncedCallback(fetchHistoricalData, 1500, { + maxWait: 5000, + }); + const assetColors: Record = useMemo(() => { const usedColors = new Set(); return assets.reduce((colors, asset) => { @@ -176,14 +192,20 @@ export const PortfolioChart = () => { ); }, [hideAssets, hiddenAssets, toggleAsset, toggleAllAssets]); + const handleUpdateDateRange = useCallback((newRange: DateRange) => { + updateDateRange(newRange); + + debouncedFetchHistoricalData(newRange.startDate, newRange.endDate); + }, [updateDateRange, debouncedFetchHistoricalData]); + const ChartContent = useCallback(() => ( <>
updateDateRange({ ...dateRange, startDate: date })} - onEndDateChange={(date) => updateDateRange({ ...dateRange, endDate: date })} + onStartDateChange={(date) => handleUpdateDateRange({ ...dateRange, startDate: date })} + onEndDateChange={(date) => handleUpdateDateRange({ ...dateRange, endDate: date })} />