首页 > 解决方案 > 在作为道具数据传递的反应中重新加载图表数据

问题描述

您好,我正在尝试重新加载在反应组件中作为道具数据传递的数据。我正在为图表使用轻量级图表库。但我认为它与库本身无关,只是缺少重新加载图表数据的文档。我对特定组件的反应代码如下所示:

import React, { useEffect, useRef } from 'react';
import ReactDOM from 'react-dom';
import { createChart, CrosshairMode } from 'lightweight-charts';


export function ChartComponent(props) {
    const chartContainerRef = useRef();
    const chart = useRef();
    const resizeObserver = useRef();
    const candleSeriesRef = useRef();

    useEffect(() => {

      chart.current = createChart(chartContainerRef.current, {
        width: chartContainerRef.current.clientWidth,
        height: chartContainerRef.current.clientHeight,
        layout: {
          backgroundColor: '#253248',
          textColor: 'rgba(255, 255, 255, 0.9)',
        },
        grid: {
          vertLines: {
            color: '#334158',
          },
          horzLines: {
            color: '#334158',
          },
        },
        crosshair: {
          mode: CrosshairMode.Normal,
        },
        priceScale: {
          borderColor: '#485c7b',
        },
        timeScale: {
          borderColor: '#485c7b',
        },
      });
  
      candleSeriesRef.current = chart.current.addCandlestickSeries({
        upColor: '#4bffb5',
        downColor: '#ff4976',
        borderDownColor: '#ff4976',
        borderUpColor: '#4bffb5',
        wickDownColor: '#838ca1',
        wickUpColor: '#838ca1',
      });
  
      candleSeriesRef.current.setData(props.data);
    }, []);
  

  return (
    <div ref={chartContainerRef} className="chart-container" />
  );
}

组件使用:

    {/* Chart */}
    <Grid item xs={12}>
      <Paper className={fixedHeightPaper}>
        <ChartComponent data={data}/>
      </Paper>
    </Grid>

当我从父视图更改数据时,数据没有改变。我还尝试在没有最后一个括号的情况下调用组件 useEffect ,因此每次道具更改时都会调用它,但我只是在原始图表下堆叠新图表。我想要实现的只是从父端更改整个数据并重新加载图表。

标签: javascriptreactjscharts

解决方案


第一:了解 React Hooks

useEffect react hook 让你在 prop/DOM mount/DOM unmount 或 state 改变时执行一个动作,所以

useEffect(() => {
    //this function will be called every time data prop changes
    return () => {
        //this function will be called after the above function finishes.
        //here you can do cleanup.
    }
},[props.data]) //this array is for all the dependencies/values to watch.

useEffect 挂钩根据依赖项调用函数,

[]           = function will be called on mount and cleanup on unmount
[some value] = function will be called on mount and only when the value changes
no value     = function will be called on every render

二:解决方案

import React, { useEffect, useRef } from 'react';
import ReactDOM from 'react-dom';
import { createChart, CrosshairMode } from 'lightweight-charts';


export function ChartComponent(props) {
    const chartContainerRef = useRef();
    const chart = useRef();
    const resizeObserver = useRef();
    const candleSeriesRef = useRef();

    useEffect(() => {

      chart.current = createChart(chartContainerRef.current, {
        width: chartContainerRef.current.clientWidth,
        height: chartContainerRef.current.clientHeight,
        layout: {
          backgroundColor: '#253248',
          textColor: 'rgba(255, 255, 255, 0.9)',
        },
        grid: {
          vertLines: {
            color: '#334158',
          },
          horzLines: {
            color: '#334158',
          },
        },
        crosshair: {
          mode: CrosshairMode.Normal,
        },
        priceScale: {
          borderColor: '#485c7b',
        },
        timeScale: {
          borderColor: '#485c7b',
        },
      });
  
      candleSeriesRef.current = chart.current.addCandlestickSeries({
        upColor: '#4bffb5',
        downColor: '#ff4976',
        borderDownColor: '#ff4976',
        borderUpColor: '#4bffb5',
        wickDownColor: '#838ca1',
        wickUpColor: '#838ca1',
      });
  
      candleSeriesRef.current.setData(props.data);
    }, [props.data]);
  

  return (
    <div ref={chartContainerRef} className="chart-container" />
  );
}

第三:改进的解决方案

每次数据道具更改时重新创建图表太昂贵了。

import React, { useEffect, useRef } from 'react';
import ReactDOM from 'react-dom';
import { createChart, CrosshairMode } from 'lightweight-charts';


export function ChartComponent(props) {
    const chartContainerRef = useRef();
    const chart = useRef();
    const resizeObserver = useRef();
    const candleSeriesRef = useRef();
    
    //this effect will be called only once, since there is no dependencies.
    useEffect(() => {

      chart.current = createChart(chartContainerRef.current, {
        width: chartContainerRef.current.clientWidth,
        height: chartContainerRef.current.clientHeight,
        layout: {
          backgroundColor: '#253248',
          textColor: 'rgba(255, 255, 255, 0.9)',
        },
        grid: {
          vertLines: {
            color: '#334158',
          },
          horzLines: {
            color: '#334158',
          },
        },
        crosshair: {
          mode: CrosshairMode.Normal,
        },
        priceScale: {
          borderColor: '#485c7b',
        },
        timeScale: {
          borderColor: '#485c7b',
        },
      });
  
      candleSeriesRef.current = chart.current.addCandlestickSeries({
        upColor: '#4bffb5',
        downColor: '#ff4976',
        borderDownColor: '#ff4976',
        borderUpColor: '#4bffb5',
        wickDownColor: '#838ca1',
        wickUpColor: '#838ca1',
      });
    }, []);
    
    //this effect will be called every time data props changes
    useEffect(() => {
      if(chart.current)
      candleSeriesRef.current.setData(props.data);
    }, [props.data]);
  

  return (
    <div ref={chartContainerRef} className="chart-container" />
  );
}

reactjs 文档解释得更好,https: //reactjs.org/docs/hooks-effect.html


推荐阅读