Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions Common/cpp/SharedItems/ShareableValue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
272 changes: 248 additions & 24 deletions FabricExample/src/WorkletExample.tsx
Original file line number Diff line number Diff line change
@@ -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 <Button onPress={handlePress} title="runOnUI demo" />;
}

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 <Button onPress={handlePress} title="runOnUI + runOnJS demo" />;
}

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 (
<Button onPress={handlePress} title="useDerivedValue + runOnJS demo" />
);
}

function ThrowErrorDemo() {
const handlePress = () => {
throw new Error('Hello world from React Native JS!');
};

return <Button onPress={handlePress} title="Throw error on JS" />;
}

function ThrowErrorWorkletDemo() {
const someWorklet = () => {
'worklet';
throw new Error('Hello world from worklet!');
};

const handlePress = () => {
runOnUI(someWorklet)();
};

return <Button onPress={handlePress} title="Throw error from worklet" />;
}

function ThrowErrorNestedWorkletDemo() {
const innerWorklet = () => {
'worklet';
throw new Error('Hello world from nested worklet!');
};

const outerWorklet = () => {
'worklet';
innerWorklet();
};

const handlePress = () => {
runOnUI(outerWorklet)();
};

return (
<Button onPress={handlePress} title="Throw error from nested worklet" />
);
}

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 (
<View style={styles.container}>
<Button onPress={handlePress1} title="runOnUI demo" />
<Button onPress={handlePress2} title="runOnJS demo" />
<Button onPress={handlePress} title="Throw error from useAnimatedStyle" />
);
}

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 (
<Button onPress={handlePress} title="Throw error from useDerivedValue" />
);
}

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 (
<Button onPress={handlePress} title="Throw error from useFrameCallback" />
);
}

function ThrowErrorFromGestureDetectorDemo() {
const gesture = Gesture.Pan().onChange(() => {
throw Error('Hello world from GestureDetector callback!');
});

return (
<GestureDetector gesture={gesture}>
<View style={{ width: 100, height: 100, backgroundColor: 'tomato' }}>
<Text>GestureDetector</Text>
</View>
</GestureDetector>
);
}

function ThrowErrorFromUseAnimatedGestureHandlerDemo() {
const gestureHandler = useAnimatedGestureHandler({
onActive: () => {
throw Error('Hello world from useAnimatedGestureHandler');
},
});

return (
<PanGestureHandler onGestureEvent={gestureHandler}>
<Animated.View
style={{ width: 100, height: 100, backgroundColor: 'gold' }}>
<Text>PanGestureHandler + useAnimatedGestureHandler</Text>
</Animated.View>
</PanGestureHandler>
);
}

function ThrowErrorFromUseAnimatedScrollHandlerDemo() {
const scrollHandler = useAnimatedScrollHandler(() => {
throw Error('Hello world from useAnimatedScrollHandler');
});

return (
<View style={{ height: 100 }}>
<Animated.ScrollView scrollEventThrottle={16} onScroll={scrollHandler}>
<View
style={{
width: 100,
height: 500,
backgroundColor: 'lime',
}}>
<Text>useAnimatedScrollHandler</Text>
</View>
</Animated.ScrollView>
</View>
);
}

function ThrowErrorFromUseScrollViewOffsetDemo() {
const aref = useAnimatedRef<Animated.ScrollView>();

const offset = useScrollViewOffset(aref);

useAnimatedStyle(() => {
if (_WORKLET && offset.value > 0) {
throw Error('Hello world from useScrollViewOffset');
}
return {};
});

return (
<View style={{ height: 100 }}>
<Animated.ScrollView scrollEventThrottle={16} ref={aref}>
<View
style={{
width: 100,
height: 500,
backgroundColor: 'cyan',
}}>
<Text>useScrollViewOffset + useAnimatedStyle</Text>
</View>
</Animated.ScrollView>
</View>
);
}

const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
});
export default function WorkletExample() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<RunOnUIDemo />
<RunOnUIRunOnJSDemo />
<UseDerivedValueRunOnJSDemo />
<ThrowErrorDemo />
<ThrowErrorWorkletDemo />
<ThrowErrorNestedWorkletDemo />
<ThrowErrorFromUseAnimatedStyleDemo />
<ThrowErrorFromUseDerivedValueDemo />
<ThrowErrorFromUseFrameCallbackDemo />
<ThrowErrorFromGestureDetectorDemo />
<ThrowErrorFromUseAnimatedGestureHandlerDemo />
<ThrowErrorFromUseAnimatedScrollHandlerDemo />
<ThrowErrorFromUseScrollViewOffsetDemo />
</View>
);
}
7 changes: 3 additions & 4 deletions android/src/main/cpp/AndroidErrorHandler.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "AndroidErrorHandler.h"
#include <fbjni/fbjni.h>
#include <exception>
#include <string>
#include "Logger.h"

Expand All @@ -17,11 +18,9 @@ void AndroidErrorHandler::raiseSpec() {
return;
}

static const auto cls = javaClassStatic();
static auto method = cls->getStaticMethod<void(std::string)>("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<Scheduler> AndroidErrorHandler::getScheduler() {
Expand Down
5 changes: 1 addition & 4 deletions android/src/main/cpp/AndroidErrorHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,12 @@

namespace reanimated {

class AndroidErrorHandler : public JavaClass<AndroidErrorHandler>,
public ErrorHandler {
class AndroidErrorHandler : public ErrorHandler {
std::shared_ptr<ErrorWrapper> error;
std::shared_ptr<Scheduler> scheduler;
void raiseSpec() override;

public:
static auto constexpr kJavaDescriptor =
"Lcom/swmansion/reanimated/AndroidErrorHandler;";
explicit AndroidErrorHandler(std::shared_ptr<Scheduler> scheduler);
std::shared_ptr<Scheduler> getScheduler() override;
std::shared_ptr<ErrorWrapper> getError() override;
Expand Down

This file was deleted.