diff --git a/Common/cpp/SharedItems/ShareableValue.cpp b/Common/cpp/SharedItems/ShareableValue.cpp
index a987dcf6634b..a1c77e9e08c1 100644
--- a/Common/cpp/SharedItems/ShareableValue.cpp
+++ b/Common/cpp/SharedItems/ShareableValue.cpp
@@ -414,8 +414,6 @@ jsi::Value ShareableValue::toJSValue(jsi::Runtime &rt) {
} else {
res = funPtr->call(rt, args, count);
}
- } catch (jsi::JSError &e) {
- throw e;
} catch (std::exception &e) {
std::string str = e.what();
runtimeManager->errorHandler->setError(str);
diff --git a/FabricExample/src/WorkletExample.tsx b/FabricExample/src/WorkletExample.tsx
index 5783f1ad9b12..c81cf58e6446 100644
--- a/FabricExample/src/WorkletExample.tsx
+++ b/FabricExample/src/WorkletExample.tsx
@@ -1,52 +1,276 @@
+/* eslint-disable react-native/no-inline-styles */
/* global _WORKLET */
-import { Button, View, StyleSheet } from 'react-native';
-import {
+import Animated, {
runOnJS,
runOnUI,
+ useAnimatedGestureHandler,
+ useAnimatedRef,
+ useAnimatedScrollHandler,
+ useAnimatedStyle,
useDerivedValue,
+ useFrameCallback,
+ useScrollViewOffset,
useSharedValue,
} from 'react-native-reanimated';
+import { Button, Text, View } from 'react-native';
+import {
+ Gesture,
+ GestureDetector,
+ PanGestureHandler,
+} from 'react-native-gesture-handler';
import React from 'react';
-export default function WorkletExample() {
- // runOnUI demo
- const someWorklet = (number: number) => {
+declare global {
+ const _WORKLET: boolean;
+}
+
+function RunOnUIDemo() {
+ const someWorklet = (x: number) => {
'worklet';
- console.log(_WORKLET, number); // _WORKLET should be true
+ console.log(_WORKLET, x); // _WORKLET should be true
};
- const handlePress1 = () => {
+ const handlePress = () => {
runOnUI(someWorklet)(Math.random());
};
- // runOnJS demo
- const x = useSharedValue(0);
+ return ;
+}
- const someFunction = (number: number) => {
- console.log(_WORKLET, number); // _WORKLET should be false
+function RunOnUIRunOnJSDemo() {
+ const someFunction = (x: number) => {
+ console.log(_WORKLET, x); // _WORKLET should be false
+ };
+
+ const someWorklet = (x: number) => {
+ 'worklet';
+ console.log(_WORKLET, x); // _WORKLET should be true
+ runOnJS(someFunction)(x);
+ };
+
+ const handlePress = () => {
+ runOnUI(someWorklet)(Math.random());
+ };
+
+ return ;
+}
+
+function UseDerivedValueRunOnJSDemo() {
+ const sv = useSharedValue(0);
+
+ const someFunction = (x: number) => {
+ console.log(_WORKLET, x); // _WORKLET should be false
};
useDerivedValue(() => {
- runOnJS(someFunction)(x.value);
+ console.log(_WORKLET, sv.value);
+ runOnJS(someFunction)(sv.value);
+ });
+
+ const handlePress = () => {
+ sv.value = 1 + Math.random();
+ };
+
+ return (
+
+ );
+}
+
+function ThrowErrorDemo() {
+ const handlePress = () => {
+ throw new Error('Hello world from React Native JS!');
+ };
+
+ return ;
+}
+
+function ThrowErrorWorkletDemo() {
+ const someWorklet = () => {
+ 'worklet';
+ throw new Error('Hello world from worklet!');
+ };
+
+ const handlePress = () => {
+ runOnUI(someWorklet)();
+ };
+
+ return ;
+}
+
+function ThrowErrorNestedWorkletDemo() {
+ const innerWorklet = () => {
+ 'worklet';
+ throw new Error('Hello world from nested worklet!');
+ };
+
+ const outerWorklet = () => {
+ 'worklet';
+ innerWorklet();
+ };
+
+ const handlePress = () => {
+ runOnUI(outerWorklet)();
+ };
+
+ return (
+
+ );
+}
+
+function ThrowErrorFromUseAnimatedStyleDemo() {
+ const sv = useSharedValue(0);
+
+ useAnimatedStyle(() => {
+ if (!_WORKLET || sv.value === 0) {
+ return {}; // prevent throwing error on first render or from JS context
+ }
+ throw new Error('Hello world from useAnimatedStyle!');
});
- const handlePress2 = () => {
- x.value = Math.random();
+ const handlePress = () => {
+ sv.value = 1 + Math.random();
};
return (
-
-
-
+
+ );
+}
+
+function ThrowErrorFromUseDerivedValueDemo() {
+ const sv = useSharedValue(0);
+
+ useDerivedValue(() => {
+ if (!_WORKLET || sv.value === 0) {
+ return {}; // prevent throwing error on first render or from JS context
+ }
+ throw new Error('Hello world from useDerivedValue!');
+ }, [sv]);
+
+ const handlePress = () => {
+ sv.value = 1 + Math.random();
+ };
+
+ return (
+
+ );
+}
+
+function ThrowErrorFromUseFrameCallbackDemo() {
+ const sv = useSharedValue(false);
+
+ useFrameCallback(() => {
+ if (sv.value) {
+ sv.value = false;
+ throw new Error('Hello world from useFrameCallback!');
+ }
+ }, true);
+
+ const handlePress = () => {
+ sv.value = true;
+ };
+
+ return (
+
+ );
+}
+
+function ThrowErrorFromGestureDetectorDemo() {
+ const gesture = Gesture.Pan().onChange(() => {
+ throw Error('Hello world from GestureDetector callback!');
+ });
+
+ return (
+
+
+ GestureDetector
+
+
+ );
+}
+
+function ThrowErrorFromUseAnimatedGestureHandlerDemo() {
+ const gestureHandler = useAnimatedGestureHandler({
+ onActive: () => {
+ throw Error('Hello world from useAnimatedGestureHandler');
+ },
+ });
+
+ return (
+
+
+ PanGestureHandler + useAnimatedGestureHandler
+
+
+ );
+}
+
+function ThrowErrorFromUseAnimatedScrollHandlerDemo() {
+ const scrollHandler = useAnimatedScrollHandler(() => {
+ throw Error('Hello world from useAnimatedScrollHandler');
+ });
+
+ return (
+
+
+
+ useAnimatedScrollHandler
+
+
+
+ );
+}
+
+function ThrowErrorFromUseScrollViewOffsetDemo() {
+ const aref = useAnimatedRef();
+
+ const offset = useScrollViewOffset(aref);
+
+ useAnimatedStyle(() => {
+ if (_WORKLET && offset.value > 0) {
+ throw Error('Hello world from useScrollViewOffset');
+ }
+ return {};
+ });
+
+ return (
+
+
+
+ useScrollViewOffset + useAnimatedStyle
+
+
);
}
-const styles = StyleSheet.create({
- container: {
- flex: 1,
- alignItems: 'center',
- justifyContent: 'center',
- },
-});
+export default function WorkletExample() {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/android/src/main/cpp/AndroidErrorHandler.cpp b/android/src/main/cpp/AndroidErrorHandler.cpp
index 91af18c0c902..fb1386fcadfa 100644
--- a/android/src/main/cpp/AndroidErrorHandler.cpp
+++ b/android/src/main/cpp/AndroidErrorHandler.cpp
@@ -1,5 +1,6 @@
#include "AndroidErrorHandler.h"
#include
+#include
#include
#include "Logger.h"
@@ -17,11 +18,9 @@ void AndroidErrorHandler::raiseSpec() {
return;
}
- static const auto cls = javaClassStatic();
- static auto method = cls->getStaticMethod("raise");
- method(cls, error->message);
-
+ // mark error as handled before this method throws exception
this->error->handled = true;
+ throw std::runtime_error(this->error->message);
}
std::shared_ptr AndroidErrorHandler::getScheduler() {
diff --git a/android/src/main/cpp/AndroidErrorHandler.h b/android/src/main/cpp/AndroidErrorHandler.h
index 37db3ad00165..5db143935077 100644
--- a/android/src/main/cpp/AndroidErrorHandler.h
+++ b/android/src/main/cpp/AndroidErrorHandler.h
@@ -11,15 +11,12 @@
namespace reanimated {
-class AndroidErrorHandler : public JavaClass,
- public ErrorHandler {
+class AndroidErrorHandler : public ErrorHandler {
std::shared_ptr error;
std::shared_ptr scheduler;
void raiseSpec() override;
public:
- static auto constexpr kJavaDescriptor =
- "Lcom/swmansion/reanimated/AndroidErrorHandler;";
explicit AndroidErrorHandler(std::shared_ptr scheduler);
std::shared_ptr getScheduler() override;
std::shared_ptr getError() override;
diff --git a/android/src/main/java/com/swmansion/reanimated/AndroidErrorHandler.java b/android/src/main/java/com/swmansion/reanimated/AndroidErrorHandler.java
deleted file mode 100644
index 47365f8e76bd..000000000000
--- a/android/src/main/java/com/swmansion/reanimated/AndroidErrorHandler.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package com.swmansion.reanimated;
-
-public class AndroidErrorHandler {
-
- public static void raise(String message) {
- throw new RuntimeException(message);
- }
-}