Skip to main content

Guide

Victory Native vs React Native Chart Kit vs 2026

Victory Native XL vs React Native Chart Kit vs Apache ECharts for React Native compared. Skia rendering, chart types, TypeScript, performance, and now.

·PkgPulse Team·
0

Victory Native vs React Native Chart Kit vs ECharts: Mobile Charts 2026

TL;DR

Data visualization on mobile is harder than web — no SVG in the native renderer, performance constraints on 60fps animations, and touch interactions that feel native. Victory Native XL (the rewritten version using React Native Skia) renders charts directly on the GPU via Skia canvas — smooth 60fps animations, declarative API, and full TypeScript types; it's the modern choice for performant React Native charts. React Native Chart Kit is the pragmatic option — uses SVG via react-native-svg, covers the most common chart types with minimal configuration, and has been the community default for years despite limited customization. Apache ECharts for React Native brings the full power of the ECharts ecosystem — 20+ chart types, rich interactions, WebView-based rendering; best when you need advanced chart types or are already using ECharts on web. For performant, customizable charts with Skia: Victory Native XL. For quick standard charts with SVG: React Native Chart Kit. For advanced chart types ported from a web ECharts implementation: Apache ECharts.

Key Takeaways

  • Victory Native XL uses React Native Skia — GPU-accelerated canvas, not SVG
  • React Native Chart Kit uses SVG — via react-native-svg, more compatible
  • Apache ECharts uses WebView — full web ECharts in a WebView; most chart variety
  • Victory Native XL supports Reanimated — gesture-driven interactions (pan, zoom)
  • React Native Chart Kit: no live updates — static charts, no built-in animation
  • ECharts React Native: 20+ chart types — map, sankey, sunburst, candlestick, etc.
  • Victory Native XL is a complete rewrite — not backward-compatible with Victory Native v36

Chart Type Coverage

Bar chart          → All three ✅
Line chart         → All three ✅
Pie / Donut        → All three ✅
Area chart         → Victory Native XL, RN Chart Kit ✅
Scatter plot       → Victory Native XL, ECharts ✅
Candlestick        → ECharts ✅
Heatmap            → ECharts ✅
Sankey diagram     → ECharts ✅
Radar chart        → ECharts, Victory Native XL ✅
Map / Geo          → ECharts ✅
Progress ring      → Victory Native XL ✅
Sparkline          → Victory Native XL ✅

Victory Native XL: Skia-Powered Charts

Victory Native XL (v40+) is a complete rewrite of Victory Native using React Native Skia for direct GPU canvas rendering. It supports gesture-driven interactions via react-native-gesture-handler and react-native-reanimated.

Installation

npm install victory-native
# Required peer dependencies:
npm install react-native-skia react-native-reanimated react-native-gesture-handler
npx pod-install  # iOS

Line Chart

import { CartesianChart, Line, useChartPressState } from "victory-native";
import { Circle, useFont } from "@shopify/react-native-skia";
import { useSharedValue } from "react-native-reanimated";

const data = [
  { day: "Mon", revenue: 1200 },
  { day: "Tue", revenue: 1800 },
  { day: "Wed", revenue: 1500 },
  { day: "Thu", revenue: 2100 },
  { day: "Fri", revenue: 2400 },
  { day: "Sat", revenue: 1900 },
  { day: "Sun", revenue: 800 },
];

function RevenueChart() {
  const font = useFont(require("../assets/fonts/Inter-Regular.ttf"), 12);
  const { state, isActive } = useChartPressState({ x: "day", y: { revenue: 0 } });

  return (
    <CartesianChart
      data={data}
      xKey="day"
      yKeys={["revenue"]}
      axisOptions={{
        font,
        formatYLabel: (value) => `$${value.toLocaleString()}`,
        labelColor: "#666",
        lineColor: "#e0e0e0",
      }}
      chartPressState={state}
    >
      {({ points }) => (
        <>
          <Line
            points={points.revenue}
            color="#3b82f6"
            strokeWidth={2}
            animate={{ type: "spring" }}
          />
          {isActive && (
            <Circle
              cx={state.x.position}
              cy={state.y.revenue.position}
              r={8}
              color="#3b82f6"
            />
          )}
        </>
      )}
    </CartesianChart>
  );
}

Bar Chart

import { CartesianChart, Bar } from "victory-native";

function SalesBarChart() {
  return (
    <CartesianChart
      data={data}
      xKey="day"
      yKeys={["revenue"]}
      domainPadding={{ left: 20, right: 20, top: 20 }}
    >
      {({ points, chartBounds }) => (
        <Bar
          chartBounds={chartBounds}
          points={points.revenue}
          color="#3b82f6"
          roundedCorners={{ topLeft: 4, topRight: 4 }}
          animate={{ type: "spring", duration: 300 }}
        />
      )}
    </CartesianChart>
  );
}

Pie / Donut Chart

import { PieChart } from "victory-native";

const pieData = [
  { label: "Direct", value: 40, color: "#3b82f6" },
  { label: "Organic", value: 25, color: "#10b981" },
  { label: "Paid", value: 20, color: "#f59e0b" },
  { label: "Referral", value: 15, color: "#ef4444" },
];

function TrafficSourceChart() {
  return (
    <PieChart
      data={pieData}
      labelKey="label"
      valueKey="value"
      colorKey="color"
      outerRadius="80%"
      innerRadius="50%"  // Donut chart
      animate={{ type: "spring" }}
    />
  );
}

Interactive Tooltip

import { CartesianChart, Line } from "victory-native";
import { useChartPressState } from "victory-native";
import Animated, { useAnimatedStyle, useDerivedValue } from "react-native-reanimated";

function InteractiveChart() {
  const { state, isActive } = useChartPressState({ x: "day", y: { revenue: 0 } });

  const tooltipLabel = useDerivedValue(() =>
    isActive.value
      ? `${state.x.value.value}: $${state.y.revenue.value.value.toFixed(0)}`
      : ""
  );

  return (
    <View>
      {/* Tooltip */}
      <Animated.Text style={tooltipStyle}>{tooltipLabel}</Animated.Text>

      <CartesianChart
        data={data}
        xKey="day"
        yKeys={["revenue"]}
        chartPressState={state}
        style={{ height: 250 }}
      >
        {({ points }) => <Line points={points.revenue} color="#3b82f6" strokeWidth={2} />}
      </CartesianChart>
    </View>
  );
}

React Native Chart Kit: SVG Charts

React Native Chart Kit is the long-standing community choice for standard charts via SVG — straightforward API, covers most use cases, with react-native-svg under the hood.

Installation

npm install react-native-chart-kit react-native-svg
npx pod-install  # iOS

Line Chart

import { LineChart } from "react-native-chart-kit";
import { Dimensions } from "react-native";

const screenWidth = Dimensions.get("window").width;

const chartConfig = {
  backgroundColor: "#ffffff",
  backgroundGradientFrom: "#ffffff",
  backgroundGradientTo: "#ffffff",
  decimalPlaces: 0,
  color: (opacity = 1) => `rgba(59, 130, 246, ${opacity})`,
  labelColor: (opacity = 1) => `rgba(100, 116, 139, ${opacity})`,
  strokeWidth: 2,
  propsForDots: {
    r: "4",
    strokeWidth: "2",
    stroke: "#3b82f6",
  },
};

function RevenueLineChart() {
  return (
    <LineChart
      data={{
        labels: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
        datasets: [
          {
            data: [1200, 1800, 1500, 2100, 2400, 1900, 800],
            color: (opacity = 1) => `rgba(59, 130, 246, ${opacity})`,
            strokeWidth: 2,
          },
        ],
      }}
      width={screenWidth - 32}
      height={220}
      chartConfig={chartConfig}
      bezier  // Smooth curves
      style={{ borderRadius: 12 }}
      formatYLabel={(value) => `$${parseInt(value).toLocaleString()}`}
      onDataPointClick={({ value, index }) => {
        console.log(`Tapped: ${value} at index ${index}`);
      }}
    />
  );
}

Bar and Pie Charts

import { BarChart, PieChart, ProgressChart } from "react-native-chart-kit";

function SalesBarChart() {
  return (
    <BarChart
      data={{
        labels: ["Mon", "Tue", "Wed", "Thu", "Fri"],
        datasets: [{ data: [1200, 1800, 1500, 2100, 2400] }],
      }}
      width={screenWidth - 32}
      height={220}
      chartConfig={chartConfig}
      yAxisLabel="$"
      yAxisSuffix=""
      showValuesOnTopOfBars
    />
  );
}

function TrafficPieChart() {
  return (
    <PieChart
      data={[
        { name: "Direct", population: 40, color: "#3b82f6", legendFontColor: "#666", legendFontSize: 12 },
        { name: "Organic", population: 25, color: "#10b981", legendFontColor: "#666", legendFontSize: 12 },
        { name: "Paid", population: 20, color: "#f59e0b", legendFontColor: "#666", legendFontSize: 12 },
      ]}
      width={screenWidth - 32}
      height={200}
      chartConfig={chartConfig}
      accessor="population"
      backgroundColor="transparent"
      paddingLeft="10"
    />
  );
}

Apache ECharts for React Native: WebView Charts

ECharts for React Native wraps Apache ECharts in a WebView — full access to ECharts' 20+ chart types, themes, and interactions.

Installation

npm install @wuba/react-native-echarts react-native-webview react-native-svg
npx pod-install  # iOS

Line Chart with ECharts

import { useRef, useState, useEffect } from "react";
import { SkiaChart, SVGRenderer } from "@wuba/react-native-echarts";
import * as echarts from "echarts/core";
import { LineChart } from "echarts/charts";
import { GridComponent, TooltipComponent, LegendComponent } from "echarts/components";

// Register required components
echarts.use([SVGRenderer, LineChart, GridComponent, TooltipComponent, LegendComponent]);

function EChartsLineChart() {
  const chartRef = useRef(null);

  useEffect(() => {
    const chart = echarts.init(chartRef.current, "light", {
      renderer: "svg",
      width: 350,
      height: 250,
    });

    chart.setOption({
      tooltip: {
        trigger: "axis",
        formatter: (params: any[]) => {
          return `${params[0].axisValue}: $${params[0].value.toLocaleString()}`;
        },
      },
      xAxis: {
        type: "category",
        data: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
      },
      yAxis: {
        type: "value",
        axisLabel: { formatter: (val: number) => `$${val.toLocaleString()}` },
      },
      series: [
        {
          data: [1200, 1800, 1500, 2100, 2400, 1900, 800],
          type: "line",
          smooth: true,
          lineStyle: { width: 2, color: "#3b82f6" },
          areaStyle: { color: "rgba(59, 130, 246, 0.1)" },
        },
      ],
    });

    return () => chart.dispose();
  }, []);

  return <SkiaChart ref={chartRef} />;
}

Advanced: Candlestick Chart (Not available in other libraries)

import { CandlestickChart } from "echarts/charts";
echarts.use([CandlestickChart]);

function StockChart() {
  const chartRef = useRef(null);

  useEffect(() => {
    const chart = echarts.init(chartRef.current, "light", {
      renderer: "svg",
      width: 350,
      height: 300,
    });

    // [open, close, low, high]
    const stockData = [
      [150, 155, 148, 157],
      [155, 152, 149, 158],
      [152, 160, 151, 162],
      [160, 158, 155, 163],
      [158, 165, 156, 167],
    ];

    chart.setOption({
      xAxis: {
        data: ["Mon", "Tue", "Wed", "Thu", "Fri"],
      },
      yAxis: { scale: true },
      series: [
        {
          type: "candlestick",
          data: stockData,
          itemStyle: {
            color: "#10b981",      // Bullish
            color0: "#ef4444",     // Bearish
            borderColor: "#10b981",
            borderColor0: "#ef4444",
          },
        },
      ],
    });

    return () => chart.dispose();
  }, []);

  return <SkiaChart ref={chartRef} />;
}

Feature Comparison

FeatureVictory Native XLRN Chart KitECharts RN
RendererSkia (GPU canvas)SVGWebView/SVG
Performance✅ Excellent✅ Good⚠️ WebView overhead
Chart types8820+
Gesture/zoom✅ Reanimated
Animations✅ SpringLimited✅ Rich
Candlestick
Heatmap
Sankey/Flow
TypeScript✅ Excellent✅ Good✅ Good
Bundle sizeMediumSmallLarge (ECharts)
Custom drawing✅ Skia canvas
GitHub stars1.6k2.5k4k

When to Use Each

Choose Victory Native XL if:

  • Performance is critical — 60fps animations with gesture-driven interactions (pan, zoom, scrub)
  • Skia canvas gives access to custom drawing alongside charts
  • Standard chart types (line, bar, area, pie, scatter) cover your needs
  • TypeScript-first, modern React Native stack (Skia + Reanimated + Gesture Handler)

Choose React Native Chart Kit if:

  • Quick standard charts without performance requirements
  • Simpler setup — just react-native-svg as a dependency
  • Community-familiar API that's been stable for years
  • No need for gesture interactions or animation beyond basic entrance animations

Choose ECharts React Native if:

  • Advanced chart types not available in other libraries (candlestick, sankey, heatmap, geo maps)
  • You're porting a web ECharts implementation to React Native
  • Rich built-in interactions (click to filter, drill-down, zoom) matter
  • WebView overhead is acceptable for your use case

Performance Benchmarks and Frame Rate Considerations

The rendering approach of each library directly determines its viability for data-dense, frequently-updating dashboards. Victory Native XL's Skia canvas renders on the GPU thread through the Fabric architecture, which means animation and data updates do not block the JavaScript thread — charts animate at 60fps even when your JS thread is processing network responses. React Native Chart Kit renders via SVG, which is composited by the native rendering pipeline and performs well for static or infrequently-updated charts, but large SVG DOM trees with hundreds of data points can cause noticeable redraws. The ECharts WebView approach introduces the most overhead: every chart.setOption() call serializes data across the WebView bridge, which adds latency proportional to data size. For dashboards that update in real-time (stock tickers, live sensor readings), Victory Native XL is the only option with the performance headroom to update at 60fps. For charts that update every few seconds or only on user action, all three libraries perform acceptably.

TypeScript Integration and Type-Safe Chart Data

Victory Native XL ships with TypeScript definitions that enforce the relationship between your data array's key names and the xKey/yKeys props — passing a key that doesn't exist in your data array is a TypeScript error at development time. The useChartPressState hook is also generic over your data shape, so state.x.value and state.y.revenue.value are properly typed based on the keys you declare. React Native Chart Kit's TypeScript support covers the component props but does not enforce that your datasets array contains numeric values — you can pass strings and only see failures at runtime. ECharts for React Native operates through the imperative chart.setOption() API, which accepts an untyped options object; there are community @types/echarts definitions but they are not enforced at the series data level. For codebases where TypeScript strictness matters throughout, Victory Native XL's type safety at the data-to-chart binding layer is a meaningful advantage.

New Architecture Requirements and Expo Compatibility

Victory Native XL requires the New Architecture (Fabric renderer + JSI) because React Native Skia uses JSI for direct communication between JavaScript and the native Skia rendering engine. This means Victory Native XL is not compatible with Expo Go (which runs the Old Architecture) — you must use a development build via npx expo run:ios or eas build. For teams still on the Old Architecture in production, this is a blocking constraint. React Native Chart Kit and ECharts for React Native both work with the Old Architecture and are compatible with Expo Go for development — this significantly lowers the barrier to adding charts to a managed Expo workflow. If your team is not yet on the New Architecture and the timeline to migrate is uncertain, React Native Chart Kit is the pragmatic choice today. If you are greenfield or have already migrated, Victory Native XL's Skia foundation positions it well for the React Native ecosystem's long-term direction.

Migration Path from React Native Chart Kit to Victory Native XL

Teams with an existing React Native Chart Kit codebase can migrate incrementally since the libraries are not coupled — you can render Victory Native XL charts in new screens while leaving existing Chart Kit charts in place. The API surface is substantially different: Chart Kit uses a data object with labels and datasets arrays, while Victory Native XL uses a flat array of typed objects with explicit key mappings. The mental model shift is from "dataset as parallel arrays" to "dataset as records," which aligns better with how data typically arrives from APIs. The setup cost of adding Skia, Reanimated, and Gesture Handler as peer dependencies is the primary friction point — these are significant native modules that require pod installation and potentially a Xcode clean build. Budget a half-day for initial setup and a few days to migrate complex chart screens with custom interactions. The payoff is charts that feel genuinely native rather than web-technology-embedded.

Methodology

Data sourced from official Victory Native documentation (commerce.nearform.com/open-source/victory-native), React Native Chart Kit GitHub repository, Apache ECharts for React Native documentation (wuba.github.io/react-native-echarts), npm download statistics as of February 2026, GitHub star counts as of February 2026, and community discussions from the React Native Discord and r/reactnative.


Related: FlashList vs FlatList vs LegendList for the list rendering performance that often houses chart data, or React Native Reanimated vs Moti vs Skia for the animation libraries that Victory Native XL is built on.

See also: React vs Vue and React vs Svelte

The 2026 JavaScript Stack Cheatsheet

One PDF: the best package for every category (ORMs, bundlers, auth, testing, state management). Used by 500+ devs. Free, updated monthly.