You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js集成Lightweight Charts出现图表重复渲染双倍实例问题

Next.js Lightweight Charts 蜡烛图重复渲染问题修复

问题描述

  • 技术栈:Next.js + Lightweight Charts 实现K线蜡烛图功能
  • 实现逻辑:
    1. 封装CandleStickChart组件,接收OHLC_Data作为props渲染K线
    2. 页面通过getServerSideProps在服务端拉取小时、日、周三个维度的行情数据
    3. 使用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,
        },
    };
}

问题成因

问题由两个因素共同导致:

  1. Next.js默认在开发环境开启React严格模式(Strict Mode),严格模式下组件首次挂载时会执行挂载→卸载→重新挂载的流程,用于提前暴露未正确清理副作用的代码问题
  2. 原有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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 05:06:24