From 1ed574680f72a8c259bf0c3665466ad3b066d89f Mon Sep 17 00:00:00 2001 From: Mackie Date: Sun, 7 Jun 2026 22:56:36 +0800 Subject: [PATCH] first --- package.json | 1 + pnpm-lock.yaml | 20 +++++ src/App.tsx | 152 ++++++++-------------------------- src/hooks/useDashboardData.ts | 23 +++++ src/worker/data.worker.ts | 13 +++ vite.config.ts | 12 ++- 6 files changed, 100 insertions(+), 121 deletions(-) create mode 100644 src/hooks/useDashboardData.ts create mode 100644 src/worker/data.worker.ts diff --git a/package.json b/package.json index 6d1498e..041635f 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "preview": "vite preview" }, "dependencies": { + "@tanstack/react-virtual": "^3.14.2", "react": "^19.2.6", "react-dom": "^19.2.6" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3c43284..64f849d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,6 +8,9 @@ importers: .: dependencies: + '@tanstack/react-virtual': + specifier: ^3.14.2 + version: 3.14.2(react-dom@19.2.7(react@19.2.7))(react@19.2.7) react: specifier: ^19.2.6 version: 19.2.7 @@ -312,6 +315,15 @@ packages: '@rolldown/pluginutils@1.0.1': resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} + '@tanstack/react-virtual@3.14.2': + resolution: {integrity: sha512-IpWnmCLvuymRfeeLNVXIzNEYBFLpd3drVIS91sqV78VTZFyldlChkOocZRCPp1B+Wnk09bcLNme8WaMU/9/9bQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + '@tanstack/virtual-core@3.17.0': + resolution: {integrity: sha512-gOxY/hFkPh/XQYhnThBHzkbkX3Ed+z/iushyz+R+JAr213aXxUDgQoTgTdrDpBSRsjFM73P/KfUyWmaF9WHMkQ==} + '@tybys/wasm-util@0.10.2': resolution: {integrity: sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==} @@ -1172,6 +1184,14 @@ snapshots: '@rolldown/pluginutils@1.0.1': {} + '@tanstack/react-virtual@3.14.2(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@tanstack/virtual-core': 3.17.0 + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + + '@tanstack/virtual-core@3.17.0': {} + '@tybys/wasm-util@0.10.2': dependencies: tslib: 2.8.1 diff --git a/src/App.tsx b/src/App.tsx index a66b5ef..e30faaa 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,122 +1,40 @@ -import { useState } from 'react' -import reactLogo from './assets/react.svg' -import viteLogo from './assets/vite.svg' -import heroImg from './assets/hero.png' -import './App.css' +import { useRef } from 'react'; +import { useVirtualizer } from '@tanstack/react-virtual'; +import { useDashboardData } from './hooks/useDashboardData'; +import './App.css'; -function App() { - const [count, setCount] = useState(0) +export default function App() { + const data = useDashboardData(); + const parentRef = useRef(null); + + const rowVirtualizer = useVirtualizer({ + count: data.length, + getScrollElement: () => parentRef.current, + estimateSize: () => 35, // Consistent row height + }); return ( - <> -
-
- - React logo - Vite logo -
-
-

Get started

-

- Edit src/App.tsx and save to test HMR -

-
- -
- -
- -
-
- -

Documentation

-

Your questions, answered

- + {rowVirtualizer.getVirtualItems().map((virtualRow) => ( +
+ {data[virtualRow.index].symbol} + ${data[virtualRow.index].price} +
+ ))}
-
- -

Connect with us

-

Join the Vite community

- -
-
- -
-
- - ) -} - -export default App + + + ); +} \ No newline at end of file diff --git a/src/hooks/useDashboardData.ts b/src/hooks/useDashboardData.ts new file mode 100644 index 0000000..c0d2c9d --- /dev/null +++ b/src/hooks/useDashboardData.ts @@ -0,0 +1,23 @@ +import { useEffect, useState } from 'react'; + +export const useDashboardData = () => { + const [data, setData] = useState([]); + + useEffect(() => { + // Instantiate the worker + const worker = new Worker(new URL('../worker/data.worker.ts', import.meta.url), { + type: 'module', + }); + + worker.onmessage = (event) => { + if (event.data.type === 'BATCH_UPDATE') { + // Keep only the latest 1000 items to prevent memory bloat + setData((prev) => [...event.data.payload, ...prev].slice(0, 1000)); + } + }; + + return () => worker.terminate(); + }, []); + + return data; +}; \ No newline at end of file diff --git a/src/worker/data.worker.ts b/src/worker/data.worker.ts new file mode 100644 index 0000000..f10341f --- /dev/null +++ b/src/worker/data.worker.ts @@ -0,0 +1,13 @@ +// src/worker/data.worker.ts +const generateUpdate = () => ({ + id: Math.random().toString(36).substring(7), + symbol: "BTC/USD", + price: (Math.random() * 50000).toFixed(2), + timestamp: Date.now(), +}); + +// Stream updates every 16ms (target ~60fps) +setInterval(() => { + const updates = Array.from({ length: 5 }, generateUpdate); + self.postMessage({ type: 'BATCH_UPDATE', payload: updates }); +}, 16); \ No newline at end of file diff --git a/vite.config.ts b/vite.config.ts index 8b0f57b..4674fa4 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,7 +1,11 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; -// https://vite.dev/config/ export default defineConfig({ plugins: [react()], -}) + worker: { + // This ensures your worker is bundled as an ES module, + // which is required for modern browsers and deployment. + format: 'es', + }, +}); \ No newline at end of file