Reputation: 49
I'm working on a data visualization app using React and Recharts, and I'm facing performance issues when rendering large datasets. My data consists of three variables: voltage, current, and distance, each containing at least 20,000 data points. While fetching the data from the database (MariaDB) via a Node.js server is quick, the bottleneck occurs during rendering the data in the chart.
Here’s an overview of how I’m currently managing the data and rendering the chart:
import { useState, useMemo } from 'react'
import {
LineChart,
Line,
XAxis,
YAxis,
CartesianGrid,
Tooltip,
Legend,
ResponsiveContainer,
Brush,
ReferenceLine,
} from 'recharts'
import { useAppSelector } from '@/Hooks/useReduxHook'
import type { RootState } from '@/store'
import { Switch } from '@/components/ui/switch'
interface ChartDataItem {
time: number
voltage: number
current: number
distance: number
}
const CenteredZeroProcessDataChart: React.FC = () => {
const { currentWeld } = useAppSelector((state) => state.weld)
const [isZoomingEnabled, setZoomingEnabled] = useState(true)
const { theme } = useAppSelector((state: RootState) => state.themeState)
const [brushDomain, setBrushDomain] = useState<[number, number] | null>(null)
const data: ChartDataItem[] = useMemo(() => {
if (!currentWeld) return []
const curve1Data = currentWeld.Curves_Data.curves.curve_1.curveData || []
const curve2Data = currentWeld.Curves_Data.curves.curve_2.curveData || []
const curve3Data = currentWeld.Curves_Data.curves.curve_3.curveData || []
const maxLength = Math.max(
curve1Data.length,
curve2Data.length,
curve3Data.length
)
return Array.from({ length: maxLength }, (_, i) => ({
time: i,
current: curve1Data[i]?.y || 0,
voltage: curve2Data[i]?.y || 0,
distance: curve3Data[i]?.y || 0,
}))
}, [currentWeld])
const { maxAbsValue } = useMemo(() => {
let max = 0
data.forEach((item) => {
max = Math.max(
max,
Math.abs(item.voltage),
Math.abs(item.current),
Math.abs(item.distance)
)
})
return { maxAbsValue: max }
}, [data])
const handleToggleZooming = () => {
setZoomingEnabled((prev) => !prev)
}
const handleBrushChange = (domain: [number, number]) => {
setBrushDomain(domain)
}
return (
<div className='border-2 rounded-md px-1'>
<div className='flex justify-between'>
<div className='flex items-center mt-2 gap-x-2 py-1.5'>
<Switch
checked={isZoomingEnabled}
onCheckedChange={handleToggleZooming}
/>
<span className=''>
{isZoomingEnabled
? 'Switch to Cursor Mode'
: 'Switch to Zooming Mode'}
</span>
</div>
<div className='flex items-center mt-2 gap-x-2'>
<Switch checked={false} />
<span className=''>Soll-Kurve</span>
</div>
</div>
<div className='w-full wide:h-[40vh] desktop:h-[35vh]'>
<ResponsiveContainer width='100%' height='100%'>
<LineChart
data={data}
margin={{ top: 5, right: 30, left: 20, bottom: 5 }}
>
<CartesianGrid strokeDasharray='3 3' />
<XAxis
dataKey='time'
type='number'
domain={brushDomain || ['dataMin', 'dataMax']}
tickFormatter={(value) => value.toFixed(0)}
/>
<YAxis
domain={[-maxAbsValue, maxAbsValue]}
tickFormatter={(value) => value.toFixed(2)}
/>
<Tooltip />
<Legend />
<ReferenceLine y={0} stroke='gray' strokeDasharray='3 3' />
<Line
type='monotone'
dataKey='voltage'
stroke='#00B2D9'
dot={false}
name='Spannung (V)'
/>
<Line
type='monotone'
dataKey='current'
stroke='#D75900'
dot={false}
name='Strom (A)'
/>
<Line
type='monotone'
dataKey='distance'
stroke='#911EB4'
dot={false}
name='Weg (m)'
/>
<Brush dataKey='time' height={30} stroke='#8884d8' />
</LineChart>
</ResponsiveContainer>
</div>
</div>
)
}
export default CenteredZeroProcessDataChart
What optimizations or techniques can you recommend for handling large datasets like this efficiently in Recharts?
Additionally, any tips on improving performance with React in general for this use case would be greatly appreciated!
Upvotes: 0
Views: 71