React Native Skia: The Future of High-Performance UI
React Native has revolutionized mobile app development, but when it comes to creating complex animations and custom graphics, developers often hit performance walls. Enter React Native Skia – a game-changing library that brings Google's powerful Skia graphics engine directly to your React Native apps, enabling buttery-smooth 60fps animations and stunning visual effects.
What is React Native Skia?
React Native Skia is a 2D graphics library that provides direct access to Skia's rendering capabilities on both iOS and Android. Unlike traditional React Native animations that rely on the JavaScript bridge, Skia renders everything natively on the UI thread, eliminating performance bottlenecks and enabling truly smooth animations.
Why Skia is Taking Over
🚀 Native Performance
Skia runs directly on the native thread, bypassing the JavaScript bridge entirely. This means your animations run at true 60fps without frame drops.
🎨 Unlimited Creative Freedom
Create complex shapes, gradients, filters, and effects that would be impossible or extremely difficult with standard React Native components.
📊 Perfect for Data Visualization
Build interactive charts, graphs, and dashboards that respond smoothly to user interactions.
🔧 Developer-Friendly API
Skia's declarative API feels natural to React developers, making complex graphics surprisingly approachable.
Getting Started with React Native Skia
First, install the library:
npm install @shopify/react-native-skia react-native-reanimated
# For iOS
cd ios && pod install
Example 1: Creating a Smooth Animated Circle
Let's start with a simple but smooth animated circle that pulses:
import React from 'react';
import {useEffect} from "react";
import {Canvas, Circle} from "@shopify/react-native-skia";
import {
useSharedValue,
withRepeat,
withTiming,
} from "react-native-reanimated";
export const AnimatedCircle = () => {
const radius = useSharedValue(50);
useEffect(() => {
radius.value = withRepeat(
withTiming(80, { duration: 1000 }),
-1,
true
);
}, []);
return (
<Canvas style={{ flex: 1 }}>
<Circle
cx={150}
cy={150}
r={radius}
color="lightblue"
/>
</Canvas>
);
};
This creates a circle that smoothly grows and shrinks in an infinite loop – something that would cause performance issues with traditional Animated API at scale.
Example 2: Interactive Progress Ring
Here's a more practical example – an interactive progress ring that responds to touch:
import React, { useState } from 'react';
import { Canvas, Circle, Path, Skia } from '@shopify/react-native-skia';
import { Gesture, GestureDetector } from 'react-native-gesture-handler';
import { runOnJS } from 'react-native-reanimated';
interface ProgressRingProps {
size?: number;
strokeWidth?: number;
color?: string;
}
const ProgressRing: React.FC<ProgressRingProps> = ({ size = 200, strokeWidth = 20, color = '#007AFF' }) => {
const [progress, setProgress] = useState(0);
const center = size / 2;
const radius = center - strokeWidth / 2;
const createArcPath = (progressValue: number) => {
const path = Skia.Path.Make();
const startAngle = -Math.PI / 2;
const endAngle = startAngle + (progressValue * 2 * Math.PI);
if (progressValue > 0) {
path.addArc(
{ x: strokeWidth / 2, y: strokeWidth / 2, width: radius * 2, height: radius * 2 },
(startAngle * 180) / Math.PI,
((endAngle - startAngle) * 180) / Math.PI
);
}
return path;
};
const updateProgress = (value: number) => {
setProgress(Math.max(0, Math.min(1, value)));
};
const panGesture = Gesture.Pan()
.onUpdate((e) => {
const x = e.x - center;
const y = e.y - center;
const angle = Math.atan2(y, x) + Math.PI / 2;
const normalizedAngle = angle < 0 ? angle + 2 * Math.PI : angle;
const progressValue = normalizedAngle / (2 * Math.PI);
runOnJS(updateProgress)(progressValue);
});
return (
<GestureDetector gesture={panGesture}>
<Canvas style={{ width: size, height: size }}>
<Circle
cx={center}
cy={center}
r={radius}
style="stroke"
strokeWidth={strokeWidth}
color="#E0E0E0"
/>
{progress > 0 && (
<Path
path={createArcPath(progress)}
style="stroke"
strokeWidth={strokeWidth}
strokeCap="round"
color={color}
/>
)}
</Canvas>
</GestureDetector>
);
};
export {ProgressRing};
Example 3: Real-Time Chart Animation
One of Skia's strongest use cases is creating smooth, interactive charts:
import React, { useEffect } from 'react';
import { Canvas, Path, Skia } from '@shopify/react-native-skia';
import { useSharedValue, withTiming, useDerivedValue, Easing } from 'react-native-reanimated';
const AnimatedLineChart = ({ data }: { data: number[] }) => {
const progress = useSharedValue(0);
useEffect(() => {
progress.value = 0;
progress.value = withTiming(1, { duration: 2000, easing: Easing.out(Easing.cubic) });
}, [data]);
const path = useDerivedValue(() => {
const p = Skia.Path.Make();
if (!data.length) return p;
const max = Math.max(...data);
const min = Math.min(...data);
const range = max - min || 1;
const totalProgress = progress.value * (data.length - 1);
const completeSegments = Math.floor(totalProgress);
const partialProgress = totalProgress - completeSegments;
const getPoint = (i: number) => ({
x: (i / (data.length - 1)) * 300,
y: 200 - ((data[i] - min) / range) * 200
});
const start = getPoint(0);
p.moveTo(start.x, start.y);
for (let i = 1; i <= completeSegments && i < data.length; i++) {
const curr = getPoint(i);
const prev = getPoint(i - 1);
const cp1x = prev.x + (curr.x - prev.x) * 0.4;
const cp2x = prev.x + (curr.x - prev.x) * 0.6;
p.cubicTo(cp1x, prev.y, cp2x, curr.y, curr.x, curr.y);
}
if (partialProgress > 0 && completeSegments + 1 < data.length) {
const curr = getPoint(completeSegments + 1);
const prev = getPoint(completeSegments);
const endX = prev.x + (curr.x - prev.x) * partialProgress;
const endY = prev.y + (curr.y - prev.y) * partialProgress;
const cp1x = prev.x + (curr.x - prev.x) * 0.4 * partialProgress;
const cp2x = prev.x + (curr.x - prev.x) * 0.6 * partialProgress;
p.cubicTo(cp1x, prev.y, cp2x, endY, endX, endY);
}
return p;
});
return (
<Canvas style={{ width: 300, height: 200 }}>
<Path path={path} color="#2196F3" style="stroke" strokeWidth={4} strokeCap="round" />
</Canvas>
);
};
export default AnimatedLineChart;
// Usage
const chartData = [10, 25, 15, 40, 30, 55, 45, 60];
<AnimatedLineChart data={chartData} />
Demo
Performance Benefits in Action
Traditional React Native animations often struggle with:
- Frame drops during complex animations
- JavaScript bridge bottlenecks when updating multiple elements
- Limited styling options for custom graphics
React Native Skia solves these issues by:
- Running animations on the UI thread at native speeds
- Providing direct access to the graphics pipeline
- Offering unlimited creative possibilities with custom shapes and effects
When to Use React Native Skia
Perfect for:
- Custom charts and data visualizations
- Complex animations and transitions
- Image processing and filters
- Games and interactive graphics
- Custom UI components that need pixel-perfect control
Maybe overkill for:
- Simple fade/slide animations
- Standard UI components
- Static layouts
Getting the Most Out of Skia
Performance Tips:
- Use shared values for animations instead of state
-
Minimize re-renders by using
useDerivedValue - Batch updates when possible
- Profile your animations to identify bottlenecks
Best Practices:
- Start simple and build complexity gradually
- Leverage Skia's built-in optimizations
- Use gestures for interactive elements
- Cache complex calculations
The Future is Smooth
React Native Skia represents a fundamental shift in how we think about mobile app UI. By bringing native graphics performance to React Native, it opens up possibilities that were previously reserved for native development.
Whether you're building the next great data visualization app, creating engaging animations, or just want your app to feel incredibly smooth, React Native Skia provides the tools to make it happen – all while maintaining the developer experience you love about React Native.
The future of mobile UI is smooth, performant, and beautiful. With React Native Skia, that future is available today.
Ready to dive deeper? Check out the official React Native Skia documentation and start building your next smooth, stunning mobile experience.

Top comments (0)