1

I'need to show user feed with items where every item contain a chart. Now I use react-native-svg-charts:

<LineChart
 style={{ height: 150, position: 'relative', left: -20 }}
 data={data}
 curve={shape.curveNatural}
 svg={{ stroke: chartColor1, strokeWidth: 5 }}
 contentInset={{ top: 20, bottom: 20 }}
 showGrid={false}
 numberOfTicks={0}
 key={props.id}
 >

But when I load more then 50 items performance of the app fall down to 10-15 fps.

I think it because of many SVG's on page. Which solution do you think should I use to avoid this?

1 Answers1

2

I answered a similar question recently here: Real-time data update chart in React Native and will suggest the same here.

I've struggled with performance when plotting in React Native with all of the SVG-based libraries I've tried. I recently decided to try using a couple canvas-based plotting libraries within a WebView and had very good results. I ended up making a simple package: https://www.npmjs.com/package/@dpwiese/react-native-canvas-charts.

Should you not want to use this package and instead do it yourself, it's quite straightforward. While the package source code is probably the best resource I'll summarize the steps below:

  1. Create an HTML file and import it into your component:
    const htmlTemplate = require("./index.html");
    
    where the HTML contains the JavaScript for the charting library of choice. The linked package above currently supports Chart.js v3 and uPlot. In the steps below I'll show a Chart.js configuration.
  2. Create a ref, for example let webref.
  3. Create a WebView and onLoadEnd you can inject some JavaScript into the WebView that will configure and create your chart
    <WebView
      originWhitelist={["*"]}
      ref={r  => (webref = r)}
      source={htmlTemplate}
      onLoadEnd={() => { addChart(config) }}
    />
    
    where addChart looks something like:
    const addChart = config => {
      webref.injectJavaScript(`const el = document.createElement("canvas");
        document.body.appendChild(el);
        window.canvasLine = new Chart(el.getContext('2d'), ${JSON.stringify(config)});`);
    };
    
    and config is a valid Chart.js configuration.
  4. To update the chart data simply inject some JavaScript to update the data. In the case of Chart.js here, that'd look like:
    const setData = dataSets => {
      if (dataSets) {
        dataSets.forEach((_, i) => {
          webref.injectJavaScript(`window.canvasLine.config.data.datasets[${i}].data = ${JSON.stringify(dataSets[i])};
          window.canvasLine.update();`);
        });
      }
    };
    
    where dataSets are valid Chart.js data sets.
  5. That's it! I've only played around with these two plotting libraries via the https://www.npmjs.com/package/@dpwiese/react-native-canvas-charts package, but so far performance has been really good, even with the JSON stringification of all the passed chart data. I haven't quantified it thoroughly, but both libraries are orders of magnitude more performant than any of the SVG-based ones I've tried.
Daniel Wiese
  • 131
  • 2
  • 1
    Daniel, thanks a lot! I've found that my newbie problem was in using ScrollView, and all items with charts was rendered at the same time. When I moved to list view the problem was resolved. – Vincent Vega Mar 03 '21 at 14:06