React Native Worklets
React Native Worklets is a fundamental library providing low-level multithreading capabilities for React Native applications. It enables JavaScript functions, known as 'worklets', to execute directly on the UI thread or other background threads, bypassing the JavaScript thread bottleneck. This is crucial for achieving smooth animations, gestures, and other performance-sensitive operations that might otherwise cause UI jank. The library is closely integrated with and often used as a core component of `react-native-reanimated`. The current stable version is 0.8.1, with releases often coinciding with major `react-native-reanimated` updates. A key differentiator is its `Shareable` memory type, introduced in v0.8.0, which allows for efficient and safe data sharing between threads. It focuses on raw performance and thread control, rather than high-level animation APIs, serving as a building block for more complex libraries.
Common errors
-
Invariant Violation: A JavaScript function was called on the UI thread without being marked as a Worklet. This can happen if the Worklets Babel plugin isn't installed or configured correctly.
cause The Babel plugin responsible for transforming worklets (e.g., from `react-native-reanimated`'s Babel preset) is not configured correctly or is missing. The function executed on the UI thread was not properly compiled as a worklet.fixVerify your `babel.config.js` includes the `react-native-reanimated/plugin` (if using Reanimated) or equivalent worklet transformation plugin. Ensure the `'worklet'` directive is present at the top of any function intended to run on the UI thread. -
Error: Incompatible `react-native` version. `react-native-worklets` requires `react-native@^0.81.0`.
cause The installed version of `react-native` in your project does not match the peer dependency requirements of `react-native-worklets`.fixAdjust your `react-native` version to be within the compatible range (e.g., `npm install react-native@0.81.0` or `yarn add react-native@0.81.0`) or update `react-native-worklets` to a version compatible with your current React Native. -
ReferenceError: Can't find variable: SharedValue
cause `SharedValue` is a concept from `react-native-reanimated` that relies on `react-native-worklets`'s underlying mechanisms (like `Shareable`), but it's not directly exported by `react-native-worklets` itself. You're trying to use a Reanimated concept directly from `react-native-worklets`.fixImport `SharedValue` and related animation primitives from `react-native-reanimated`, not `react-native-worklets`. `react-native-worklets` provides the low-level threading primitives, while Reanimated builds higher-level animation APIs on top of it.
Warnings
- breaking The `react-native-worklets` package has strict peer dependencies on `react-native` versions, specifically `0.81 - 0.85`. Installing with incompatible versions will lead to build failures or runtime errors.
- gotcha To use worklets effectively, a Babel plugin (`@babel/plugin-transform-react-jsx` combined with the worklets preset or similar in `react-native-reanimated`) is typically required to transform JavaScript functions into worklets with the `'worklet'` directive. Without proper Babel configuration, worklets will not be recognized by the native modules.
- breaking Worklets cannot capture arbitrary variables from their lexical scope. Only 'capture-by-value' primitives (numbers, strings, booleans, null, undefined) or objects marked as `Shareable` (since v0.8.0) can be used. Attempting to capture complex objects or functions directly will result in runtime errors.
- gotcha When developing with Expo Go, certain native module features, including `react-native-worklets`'s static feature flags, might not be fully supported. This can lead to unexpected behavior or limitations compared to standalone builds.
Install
-
npm install react-native-worklets -
yarn add react-native-worklets -
pnpm add react-native-worklets
Imports
- runOnUI
const { runOnUI } = require('react-native-worklets');import { runOnUI } from 'react-native-worklets'; - runOnJS
const runOnJS = require('react-native-worklets').runOnJS;import { runOnJS } from 'react-native-worklets'; - makeWorklet
import makeWorklet from 'react-native-worklets';
import { makeWorklet } from 'react-native-worklets'; - Shareable
import type { Shareable } from 'react-native-worklets';
Quickstart
import { runOnUI, runOnJS, makeWorklet } from 'react-native-worklets';
import React, { useEffect, useState } from 'react';
import { Text, View, Button, StyleSheet } from 'react-native';
const calculateHeavyValue = makeWorklet((input) => {
'worklet';
let sum = 0;
for (let i = 0; i < 1_000_000_000; i++) {
sum += Math.random() * input;
}
return sum;
});
function App() {
const [result, setResult] = useState(0);
const [loading, setLoading] = useState(false);
const startCalculation = () => {
setLoading(true);
runOnUI(() => {
console.log('Calculating on UI thread...');
const heavyResult = calculateHeavyValue(10);
runOnJS(setResult)(heavyResult);
runOnJS(setLoading)(false);
console.log('Calculation finished on UI thread.');
})();
};
return (
<View style={styles.container}>
<Text style={styles.title}>Worklets Demo</Text>
<Text style={styles.resultText}>Result: {result.toFixed(2)}</Text>
<Button
title={loading ? 'Calculating...' : 'Start Heavy Calculation'}
onPress={startCalculation}
disabled={loading}
/>
{loading && <Text style={styles.loadingText}>Please wait...</Text>}
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
padding: 20,
},
title: {
fontSize: 24,
fontWeight: 'bold',
marginBottom: 20,
},
resultText: {
fontSize: 18,
marginVertical: 10,
},
loadingText: {
fontSize: 16,
color: 'gray',
marginTop: 10,
},
});
export default App;