Next.js集成Lightweight Charts出现图表重复渲染双倍实例问题
Next.js Lightweight Charts 蜡烛图重复渲染问题修复
问题描述
- 技术栈:Next.js + Lightweight Charts 实现K线蜡烛图功能
- 实现逻辑:
- 封装
CandleStickChart组件,接收OHLC_Data作为props渲染K线 - 页面通过
getServerSideProps在服务端拉取小时、日、周三个维度的行情数据 - 使用
dynamic方法动态导入CandleStickChart并关闭SSR,页面中共放置3个组件实例,预期渲染3个独立图表
- 封装
- 异常现象:实际每个图表位置都渲染出2份重复副本,总计生成6个图表,图表数据展示完全正常,仅存在重复渲染问题
原有组件实现代码
import { createChart, CrosshairMode } from 'lightweight-charts'; import { useEffect, useRef } from 'react'; const CandleStickChart = ({ OHLC_Data }) => { const chartContainerRef = useRef(null); useEffect(() => { const chart = createChart(chartContainerRef.current, { width: 700, height: 400, timeScale: { timeVisible: true, secondsVisible: false, fixLeftEdge: true, fixRightEdge: true, }, crosshair: { mode: CrosshairMode.Normal, }, }); const candleSeries = chart.addCandlestickSeries({ priceFormat: { type: 'price', minMove: 0.00001, precision: 5, }, }); candleSeries.setData(OHLC_Data); }, [OHLC_Data]); return <div ref={chartContainerRef} />; }; export default CandleStickChart;
原有页面实现代码
import { useCallback, useEffect, useState } from 'react'; import dynamic from 'next/dynamic'; import Image from 'next/image'; const CandleStickChart = dynamic( () => import('../../components/CandleStickChart'), { ssr: false } ); import { fetchTimeSeries } from '../../utils/fetchData'; const ForexPair = ({ meta, hour, day, week }) => { const { currency_base, currency_quote, symbol, type } = meta; const [logos, setLogos] = useState(null); return ( <> <CandleStickChart OHLC_Data={hour.values} /> <CandleStickChart OHLC_Data={day.values} /> <CandleStickChart OHLC_Data={week.values} /> </> ); }; export default ForexPair; export async function getServerSideProps(context) { const { params, res } = context; const { pairSymbol } = params; res.setHeader( 'Cache-Control', 'public, s-maxage=300, stale-while-revalidate=3600' ); const { meta, hour, day, week } = await fetchTimeSeries( pairSymbol.replace('-', '/') ); return { props: { meta, hour, day, week, }, }; }
问题成因
问题由两个因素共同导致:
- Next.js默认在开发环境开启React严格模式(Strict Mode),严格模式下组件首次挂载时会执行挂载→卸载→重新挂载的流程,用于提前暴露未正确清理副作用的代码问题
- 原有
CandleStickChart组件的useEffect没有编写清理逻辑:第一次挂载时调用createChart在容器DOM中生成了第一个图表实例,触发模拟卸载时该实例没有被销毁,重新挂载时又在同一个容器中生成了第二个图表实例,最终每个容器内存在2个图表,3个容器总计渲染6个
修复方案
给useEffect增加副作用清理逻辑,在组件卸载、依赖项更新前主动销毁已生成的图表实例,同时增加实例引用存储和边界判断,避免内存泄漏和重复渲染:
import { createChart, CrosshairMode } from 'lightweight-charts'; import { useEffect, useRef } from 'react'; const CandleStickChart = ({ OHLC_Data }) => { const chartContainerRef = useRef(null); // 存储图表实例,避免重新渲染时实例引用丢失 const chartRef = useRef(null); useEffect(() => { // 容器未挂载时直接返回 if (!chartContainerRef.current) return; // 存在旧实例时先销毁,避免重复生成 if (chartRef.current) { chartRef.current.remove(); } const chart = createChart(chartContainerRef.current, { width: 700, height: 400, timeScale: { timeVisible: true, secondsVisible: false, fixLeftEdge: true, fixRightEdge: true, }, crosshair: { mode: CrosshairMode.Normal, }, }); chartRef.current = chart; const candleSeries = chart.addCandlestickSeries({ priceFormat: { type: 'price', minMove: 0.00001, precision: 5, }, }); candleSeries.setData(OHLC_Data); // 副作用清理函数:销毁当前图表实例 return () => { chart.remove(); chartRef.current = null; }; }, [OHLC_Data]); return <div ref={chartContainerRef} />; }; export default CandleStickChart;
说明:该重复渲染现象仅会在开发环境出现,生产环境构建后严格模式不会触发双挂载流程,但主动清理副作用是React的标准写法,可以避免内存泄漏、DOM残留等隐性问题。
内容的提问来源于stack exchange,提问作者ryu
相关产品推荐
相关产品推荐

