diff --git a/README.md b/README.md
index 1262106..3e5a606 100644
--- a/README.md
+++ b/README.md
@@ -12,10 +12,18 @@ Low overhead monitoring of important performance metrics for React Native apps l
bun add react-native-performance-toolkit react-native-nitro-modules
```
+### Optional: Reanimated support
+
+If you want to use UI thread components and hooks (recommended for accurate FPS display), install the optional dependencies:
+
+```bash
+bun add react-native-reanimated react-native-worklets react-native-gesture-handler
+```
+
## Requirements
- React Native v0.76.0 or higher
-- Reanimated v4 or higher
+- (Optional) Reanimated v4 or higher - for UI thread components and hooks
## Usage
@@ -67,11 +75,13 @@ const SomeComponent = () => {
### Reanimated Hooks - UI Thread
+> **Note:** These features require `react-native-reanimated` and `react-native-worklets` to be installed. Import from `react-native-performance-toolkit/reanimated`.
+
To avoid the issue with not showing 0 FPS, it's recommended to use Reanimated based hooks or pre-made components. This will ensure the value is updated even if the JS thread is blocked.
```tsx
import { TextInput } from 'react-native'
-import { useFpsJsSharedValue } from 'react-native-performance-toolkit'
+import { useFpsJsSharedValue } from 'react-native-performance-toolkit/reanimated'
import Animated, {
useAnimatedReaction,
useAnimatedRef,
@@ -97,6 +107,8 @@ const SomeComponent = () => {
### Pre-made Reanimated components - UI Thread
+> **Note:** These features require `react-native-reanimated`, `react-native-worklets`, and `react-native-gesture-handler` to be installed. Import from `react-native-performance-toolkit/reanimated`.
+
For better DX, the library provides pre-made Reanimated components that run solely on the UI thread. You can use either the convenience wrappers or the flexible base component:
```tsx
@@ -106,7 +118,7 @@ import {
CpuUsageCounter,
MemoryUsageCounter,
UIThreadReanimatedCounter,
-} from 'react-native-performance-toolkit'
+} from 'react-native-performance-toolkit/reanimated'
const SomeComponent = () => {
return (
@@ -157,6 +169,8 @@ console.log('Memory Usage:', getValueFromBuffer(memoryUsageBuffer))
### Access from worklets (advanced usage)
+> **Note:** This requires `react-native-reanimated` and `react-native-worklets` to be installed.
+
You can also access the value from any worklet thread, but to do that you need to use [Nitro Modules unboxing function](https://nitro.margelo.com/docs/worklets). For more detailed implementation look for [source code of UI Reanimated hooks like `useFpsJsSharedValue`](https://github.com/Nodonisko/react-native-performance-toolkit/blob/main/src/hooks/uiThreadHooks.ts).
```tsx
@@ -187,6 +201,8 @@ const updateFps = useCallback(() => {
## API Reference
+### Core API (no additional dependencies)
+
- **Simple getters**
- `getJsFps(): number` - Returns current JS FPS (0-60)
- `getUiFps(): number` - Returns current UI FPS (0-30/60/90/120/...)
@@ -207,12 +223,6 @@ const updateFps = useCallback(() => {
- `useCpuUsage(): number` - Hook that returns current CPU usage
- `useMemoryUsage(): number` - Hook that returns current memory usage
-- **React Components (runs on UI Thread)**
- - `` - Pre-made component displaying JS FPS
- - `` - Pre-made component displaying UI FPS
- - `` - Pre-made component displaying CPU usage
- - `` - Pre-made component displaying memory usage
-
- **Buffer-based API**
- `getJsFpsBuffer(): ArrayBuffer` - Returns ArrayBuffer with JS FPS data
- `getUiFpsBuffer(): ArrayBuffer` - Returns ArrayBuffer with UI FPS data
@@ -229,6 +239,25 @@ const updateFps = useCallback(() => {
- `getDeviceMaxRefreshRate(): number`
- `getDeviceCurrentRefreshRate(): number`
+### Reanimated API (requires optional dependencies)
+
+Import from `react-native-performance-toolkit/reanimated`:
+
+- **React Components (runs on UI Thread)**
+ - `` - Pre-made component displaying JS FPS
+ - `` - Pre-made component displaying UI FPS
+ - `` - Pre-made component displaying CPU usage
+ - `` - Pre-made component displaying memory usage
+ - `` - Flexible base component
+ - `` - Draggable wrapper component
+
+- **Reanimated Hooks (UI Thread)**
+ - `useFpsJsSharedValue()` - Returns SharedValue with JS FPS
+ - `useFpsUiSharedValue()` - Returns SharedValue with UI FPS
+ - `useFpsCpuSharedValue()` - Returns SharedValue with CPU usage
+ - `useFpsMemorySharedValue()` - Returns SharedValue with memory usage
+ - `useCounterSharedValue(type)` - Generic hook for any counter type
+
## Architecture
### Low overhead tracking
diff --git a/bun.lock b/bun.lock
index 8f8bcef..83ac989 100644
--- a/bun.lock
+++ b/bun.lock
@@ -21,8 +21,16 @@
"peerDependencies": {
"react": "*",
"react-native": "*",
+ "react-native-gesture-handler": "*",
"react-native-nitro-modules": "*",
+ "react-native-reanimated": "*",
+ "react-native-worklets": "*",
},
+ "optionalPeers": [
+ "react-native-gesture-handler",
+ "react-native-reanimated",
+ "react-native-worklets",
+ ],
},
"example": {
"name": "react-native-performance-toolkit-example",
diff --git a/example/App.tsx b/example/App.tsx
index a47c6d0..e5fe4d7 100644
--- a/example/App.tsx
+++ b/example/App.tsx
@@ -14,7 +14,7 @@ import {
UIFpsCounter,
CpuUsageCounter,
MemoryUsageCounter,
-} from 'react-native-performance-toolkit';
+} from 'react-native-performance-toolkit/reanimated';
function formatValue(value: number): string {
return Number.isFinite(value) ? value.toFixed(0) : '0';
diff --git a/example/babel.config.js b/example/babel.config.js
index 5ed92ed..7bca873 100644
--- a/example/babel.config.js
+++ b/example/babel.config.js
@@ -1,21 +1,7 @@
-const path = require('path');
-const pak = require('../package.json');
-
module.exports = api => {
api.cache(true);
return {
presets: ['module:@react-native/babel-preset'],
- plugins: [
- [
- 'module-resolver',
- {
- extensions: ['.js', '.ts', '.json', '.jsx', '.tsx'],
- alias: {
- [pak.name]: path.join(__dirname, '../', pak.source),
- },
- },
- ],
- 'react-native-worklets/plugin',
- ],
+ plugins: ['react-native-worklets/plugin'],
};
};
diff --git a/example/metro.config.js b/example/metro.config.js
index d268384..aeb22f7 100644
--- a/example/metro.config.js
+++ b/example/metro.config.js
@@ -1,5 +1,6 @@
const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config');
const path = require('path');
+const pak = require('../package.json');
const root = path.resolve(__dirname, '..');
/**
@@ -10,6 +11,25 @@ const root = path.resolve(__dirname, '..');
*/
const config = {
watchFolders: [root],
+ resolver: {
+ resolveRequest: (context, moduleName, platform) => {
+ // Handle subpath import
+ if (moduleName === `${pak.name}/reanimated`) {
+ return {
+ filePath: path.resolve(__dirname, '../src/reanimated.tsx'),
+ type: 'sourceFile',
+ };
+ }
+ // Handle main package import
+ if (moduleName === pak.name) {
+ return {
+ filePath: path.resolve(__dirname, '../src/index.tsx'),
+ type: 'sourceFile',
+ };
+ }
+ return context.resolveRequest(context, moduleName, platform);
+ },
+ },
};
module.exports = mergeConfig(getDefaultConfig(__dirname), config);
\ No newline at end of file
diff --git a/example/tsconfig.json b/example/tsconfig.json
index f0eea67..afd76ab 100644
--- a/example/tsconfig.json
+++ b/example/tsconfig.json
@@ -6,7 +6,8 @@
"strict": true,
"baseUrl": ".",
"paths": {
- "react-native-performance-toolkit": ["../src"]
+ "react-native-performance-toolkit": ["../src"],
+ "react-native-performance-toolkit/reanimated": ["../src/reanimated"]
}
}
}
\ No newline at end of file
diff --git a/package.json b/package.json
index e68b696..e51b045 100644
--- a/package.json
+++ b/package.json
@@ -38,6 +38,8 @@
"ios/**/*.swift",
"app.plugin.js",
"*.podspec",
+ "reanimated.js",
+ "reanimated.d.ts",
"README.md",
"!example",
"!media"
@@ -79,6 +81,17 @@
"react-native-worklets": "*",
"react-native-gesture-handler": "*"
},
+ "peerDependenciesMeta": {
+ "react-native-reanimated": {
+ "optional": true
+ },
+ "react-native-worklets": {
+ "optional": true
+ },
+ "react-native-gesture-handler": {
+ "optional": true
+ }
+ },
"eslintConfig": {
"root": true,
"extends": [
diff --git a/reanimated.d.ts b/reanimated.d.ts
new file mode 100644
index 0000000..ca8805d
--- /dev/null
+++ b/reanimated.d.ts
@@ -0,0 +1 @@
+export * from './lib/typescript/src/reanimated'
diff --git a/reanimated.js b/reanimated.js
new file mode 100644
index 0000000..fd74978
--- /dev/null
+++ b/reanimated.js
@@ -0,0 +1 @@
+module.exports = require('./lib/commonjs/reanimated.js')
diff --git a/src/index.tsx b/src/index.tsx
index 67760fd..f3f9367 100755
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -1,7 +1,5 @@
import './specs/TurboPerformanceToolkit'
-import React from 'react'
-import { UIThreadReanimatedCounter } from './components/UIThreadReanimatedCounter'
import { PerformanceToolkit } from './hybrids'
export {
@@ -11,21 +9,6 @@ export {
PerformanceToolkit,
} from './hybrids'
-export const JSFpsCounter = () => {
- return
-}
-
-export const UIFpsCounter = () => {
- return
-}
-
-export const CpuUsageCounter = () => {
- return
-}
-export const MemoryUsageCounter = () => {
- return
-}
-
export const getDeviceMaxRefreshRate = () =>
PerformanceToolkit.getDeviceMaxRefreshRate()
diff --git a/src/reanimated.tsx b/src/reanimated.tsx
new file mode 100644
index 0000000..ddf9073
--- /dev/null
+++ b/src/reanimated.tsx
@@ -0,0 +1,22 @@
+import React from 'react'
+import { UIThreadReanimatedCounter } from './components/UIThreadReanimatedCounter'
+
+// Reanimated-dependent components
+export const JSFpsCounter = () => {
+ return
+}
+
+export const UIFpsCounter = () => {
+ return
+}
+
+export const CpuUsageCounter = () => {
+ return
+}
+
+export const MemoryUsageCounter = () => {
+ return
+}
+
+export { DraggableView } from './components/DraggableView'
+export * from './hooks/uiThreadHooks'