React-native-reanimated: What's the right way to use RunOnJS?

Created on 17 Nov 2020  路  11Comments  路  Source: software-mansion/react-native-reanimated

Description

I've looked at both the PR that added a note on RunOnJS (p.s. this doesn't appear in the docs) and I've looked at the example found here. However I still get the redbox that says Tried to synchronously call function {bound dispatchAction} from a different thread....

What I'm trying to achieve, is to update local state once the animation completes.

Code

export function someAnimation(callback?: (isCancelled: boolean) => void) {
  'worklet';
  return withSequence(
    withTiming(1, {duration: 300, easing: Easing.linear}),
    withDelay(100, withTiming(2, {duration: 500, easing: Easing.linear}, callback)),
  );
}

// Inside a functional component 
const [value, setValue] = React.useState(false);

// Trigger it here on first render
React.useEffect(() => {
    shared.value = someAnimation(runOnJS(() => setValue(true)));
  }, []);

I've tried multiple variants (based on the two links above) to no avail.
i.e.

// And then I just tried doing random stuff in hopes it works
function setTheValue() { //including const declaration
  'worklet'; // and without 'worklet'
  setValue(true);
}
// Also
shared.value = someAnimation(runOnJS(() => { 'worklet'; setValue(true)}));

Package versions

  • React: 16.13.1
  • React Native:0.63.3
  • React Native Reanimated: 2.0.0-alpha.8 & 2.0.0-alpha.9 (tried both)
鉂換uestion 馃彔 Reanimated2

Most helpful comment

The following works

function updateShare(){
  setValue(true)
}
function callback(isCancelled: boolean){
  'worklet'
  runOnJS(updateShare)()
}

React.useEffect(() => {
    shared.value = someAnimation(callback)
}, [])

All 11 comments

I too have the same issue https://github.com/software-mansion/react-native-reanimated/issues/1393#issuecomment-726790287 . Also see the same issues below

I'm unable to get the above scenario working. The snippet below does work(if it helps)..

function MyComponent({ functionToCall }) {
  ...
  const animatedStyle = useAnimatedStyle(() => {
    const size = withTiming(1, { duration: 300 }, runOnJS(functionToCall));
    return {
      height: size,
      width: size
    }
  })
  ...
}

function MainComponent() {
  return (
    <MyComponent 
      functionToCall={() => {
        // Do stuff
      }}
    />
  );
}

You can do const size = withTiming(1, { duration: 300 }, () => runOnJS(functionToCall)())

Hi @Andarius, the code snippet here works fine. It's the snippet in OP that doesn't.

I will however try your approach on my original issue. Will report back.

Sadly no, that results in the same error. Here is what I tried.

shared.value = someAnimation(() => runOnJS(someFunction)());

Why is someAnimation a worklet ? It's called from the JS Thread

I'd say my lack of understanding worklets. I removed 'worklet', however same error.

The following works

function updateShare(){
  setValue(true)
}
function callback(isCancelled: boolean){
  'worklet'
  runOnJS(updateShare)()
}

React.useEffect(() => {
    shared.value = someAnimation(callback)
}, [])

I found that I had to rewrite all of my animated components to use useSharedValue instead of useState

@Andarius this does work, thanks. A bit convoluted.

I simplified it to the following, which still seemed to work

function callback(isCancelled: boolean){
  'worklet'
  runOnJS(setValue)(true);
}

React.useEffect(() => {
    shared.value = someAnimation(callback)
}, [])

even further simplified to

React.useEffect(() => {
    shared.value = someAnimation(() => { 
      'worklet';
      runOnJS(setValue)(true)
    });
}, [])

I'll need to do some further digging to understand when and where to use worklet.

Once again, thanks for the help!

@Andarius this does work, thanks. A bit convoluted.

I simplified it to the following, which still seemed to work

function callback(isCancelled: boolean){
  'worklet'
  runOnJS(setValue)(true);
}

React.useEffect(() => {
    shared.value = someAnimation(callback)
}, [])

even further simplified to

React.useEffect(() => {
    shared.value = someAnimation(() => { 
      'worklet';
      runOnJS(setValue)(true)
    });
}, [])

I'll need to do some further digging to understand when and where to use worklet.

Once again, thanks for the help!

This doesn't work either!

Was this page helpful?
0 / 5 - 0 ratings