1

EDIT: Link to repro on Codesandbox: https://codesandbox.io/s/exciting-worker-f5j1b

I need help with an error I am getting every time I am attempting to inject new data into my chart (using lightweight charts) in React.

I suspect that the problem is related to the way that React renders and re-renders the DOM. In a parent component I do three API calls, which pass historical chart data from Binance to children components (components that have the actual charts for 4H, 2H and 1H). In the children component I have a useEffect hook that I use to create each graph and then inject the data using the lighweight charts method of chart.setData([Array]) - it also runs the webhook from Binance that I use to update the charts using the lightweight charts method chart.update({Object}).

As I said - everything actually works, except I get hundreds of errors which I would like to get rid of.

The errors occur whenever the Webhook fires (and updates the data on the chart) and whenever there is an API call in the Child component (but not the parent) -- Therefore, when I comment out the client.onmessage() and the getSignalData() API calls, I do not experience the errors, but I haven't been able to find a way to solve this.

Here's my code:

Parent

 const GraphHero = () => {
      const [fourHourData, setFourHourData] = useState("");
      const [twoHourData, setTwoHourData] = useState("");
      const [oneHourData, setOneHourData] = useState("");
      const [key, setKey] = useState("fourHour");
      const [keyTwo, setKeyTwo] = useState("fourHour");
    
      useEffect(() => {
        //get historical data for charts and pass it down as prop
        const getFourHourData = () => {
          let url = `https://api.binance.com/api/v3/klines?symbol=BTCUSDT&interval=4h&limit=1000`;
          fetch(url, {
            method: "GET",
            mode: "cors",
          })
            .then(checkStatus)
            .then(json)
            .then((response) => {
              const cData = response.map((d) => {
                return {
                  time: d[0] / 1000,
                  open: parseFloat(d[1]),
                  high: parseFloat(d[2]),
                  low: parseFloat(d[3]),
                  close: parseFloat(d[4]),
                };
              });
              setFourHourData(cData);
              console.log("Four hour API called");
            })
            .catch((error) => {
              console.log(error);
            });
        };
    
        const getTwoHourData = () => {
          let url = `https://api.binance.com/api/v3/klines?symbol=BTCUSDT&interval=2h&limit=1000`;
          fetch(url, {
            method: "GET",
            mode: "cors",
          })
            .then(checkStatus)
            .then(json)
            .then((response) => {
              const cData = response.map((d) => {
                return {
                  time: d[0] / 1000,
                  open: parseFloat(d[1]),
                  high: parseFloat(d[2]),
                  low: parseFloat(d[3]),
                  close: parseFloat(d[4]),
                };
              });
              setTwoHourData(cData);
              console.log("Two hour API called");
            })
            .catch((error) => {
              console.log(error);
            });
        };
    
        const getOneHourData = () => {
          let url = `https://api.binance.com/api/v3/klines?symbol=BTCUSDT&interval=1h&limit=1000`;
          fetch(url, {
            method: "GET",
            mode: "cors",
          })
            .then(checkStatus)
            .then(json)
            .then((response) => {
              const cData = response.map((d) => {
                return {
                  time: d[0] / 1000,
                  open: parseFloat(d[1]),
                  high: parseFloat(d[2]),
                  low: parseFloat(d[3]),
                  close: parseFloat(d[4]),
                };
              });
              setOneHourData(cData);
              console.log("One Hour API called");
            })
            .catch((error) => {
              console.log(error);
            });
        };
    
        //initialize
        getFourHourData();
        getTwoHourData();
        getOneHourData();
      }, []);
    
      return (
      //I have HTML here that I deleted to shorten the code



<FirstChart chartData={fourHourData} setHistoricalData={setFourHourData}/>
<SecondChart chartData={twoHourData} setHistoricalData={setTwoHourData}/>
<ThirdChart chartData={oneHourData} setHistoricalData={setOneHourData}/>
      );
    };
    
    export default GraphHero;

Child Component

    function FirstChart(fourHourData) {
  const [signals, setSignals] = useState("");
  const [loading, setLoading] = useState(true);
  const chartRef = React.useRef();

  useEffect(() => {
    console.log("DOM re-rendered.");
    const client = new W3CWebSocket(
      "wss://stream.binance.com:9443/ws/btcusdt@kline_4h"
    );
    const chart = createChart(chartRef.current, {
      watermark: {
        color: "white",
        visible: true,
        fontSize: 18,
        horzAlign: "left",
        vertAlign: "top",
      },
      timeScale: {
        timeVisible: true,
        borderColor: "whitesmoke",
      },
      layout: {
        backgroundColor: "#131722",
        textColor: "whitesmoke",
        fontSize: 12,
        fontFamily: "Arial",
      },
      priceScale: {
        borderColor: "whitesmoke",
      },
      grid: {
        vertLines: {
          style: 0,
          color: "rgba(70, 130, 180, 0.5)",
          visible: true,
        },
        horzLines: {
          style: 0,
          color: "rgba(70, 130, 180, 0.5)",
          visible: true,
        },
      },
    });
    const candleStickSeries = chart.addCandlestickSeries({
      upColor: "#0CCE6B",
      downColor: "#ED254E",
      borderVisible: false,
      wickVisible: true,
      borderColor: "white",
      wickColor: "white",
      borderUpColor: "#84f766",
      borderDownColor: "#ff6939",
      wickUpColor: "#84f766",
      wickDownColor: "#ff6939",
    });
    candleStickSeries.setData(fourHourData.chartData);
    client.onmessage = (event) => {
      let message = JSON.parse(event.data);
      candleStickSeries.update({
        time: message.k.t / 1000,
        open: message.k.o,
        high: message.k.h,
        low: message.k.l,
        close: message.k.c,
      });
    };

    const getSignalData = () => {
      fetch(url, {
        method: "GET",
        mode: "cors",
      })
        .then(checkStatus)
        .then(json)
        .then((response) => {
          const signalData = response.map((data) => {
            return {//Data operations I deleted because it's unrelated to chart//
            };
          });
          candleStickSeries.setMarkers(signalData);
          setSignals([...signalData.reverse()]);
          setLoading(false);
        })
        .catch((error) => {
          console.log(error);
        });
    };

    getSignalData();
    setInterval(function () {
      getSignalData();
      console.log("Fetched Long Active Chart again...");
    }, 60 * 1000);
    return () => {
      chart.remove();
    };
  }, [fourHourData]);

  return (
    <Row className="my-2">
      <Col
        lg={8}
        className="d-md-10 d-xl-block mx-auto mb-5 py-5 lightweight-chart"
        ref={chartRef}
      />
     </Row>
  );
}

export default FirstChart;

I spent hours trying to resolve this so any help would be appreciated!

Thanks

Glemin5011
  • 21
  • 2

0 Answers0