Skip to content

Fix updating SharedValue crash#4315

Merged
m-bert merged 1 commit into
mainfrom
@mbert/shared-value-crash
Jul 15, 2026
Merged

Fix updating SharedValue crash#4315
m-bert merged 1 commit into
mainfrom
@mbert/shared-value-crash

Conversation

@m-bert

@m-bert m-bert commented Jul 14, 2026

Copy link
Copy Markdown
Collaborator

Description

#4158 added useJSResponderHandler. The problem here is that notifyEnabledChanged is initialized as runOnJS, and then passed to UI. runOnJS should be executed on UI, otherwise app throws error:

Error: [Worklets] Tried to synchronously call a Remote Function. Called "anonymous" on the UI Runtime.
222-E/ReactNativeJS(28820): See https://docs.swmansion.com/react-native-worklets/docs/guides/troubleshooting#tried-to-synchronously-call-a-remote-function for more details.

Test plan

Tested on the following example:
import React, { useState } from 'react';
import { StyleSheet, Text, View } from 'react-native';
import {
  GestureDetector,
  Touchable,
  usePanGesture,
} from 'react-native-gesture-handler';
import Animated, { useSharedValue } from 'react-native-reanimated';

export const COLORS = {
  offWhite: '#f8f9ff',
  headerSeparator: '#eef0ff',
  PURPLE: '#b58df1',
  DARK_PURPLE: '#7d63d9',
  NAVY: '#001A72',
  RED: '#A41623',
  YELLOW: '#F2AF29',
  GREEN: '#0F956F',
  DARK_GREEN: '#217838',
  GRAY: '#ADB1C2',
  KINDA_RED: '#FFB2AD',
  DARK_SALMON: '#d97973',
  KINDA_YELLOW: '#FFF096',
  KINDA_GREEN: '#C4E7DB',
  KINDA_BLUE: '#A0D5EF',
  LIGHT_BLUE: '#5f97c8',
  WEB_BLUE: '#1067c4',
  ANDROID: '#34a853',
};

export default function SharedValueEnabledExample() {
  const enabled = useSharedValue(true);
  const [enabledLabel, setEnabledLabel] = useState(true);

  const pan = usePanGesture({ enabled });

  return (
    <View style={styles.container}>
      <Touchable
        onPress={() => {
          enabled.value = !enabled.value;
          setEnabledLabel(!enabledLabel);
        }}
        style={{
          padding: 16,
          backgroundColor: COLORS.WEB_BLUE,
          borderRadius: 8,
        }}
      />
      <Text style={styles.status}>{`enabled: ${enabledLabel}`}</Text>
      <GestureDetector gesture={pan}>
        <Animated.View style={[styles.box]} />
      </GestureDetector>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    paddingTop: 24,
  },
  status: {
    fontSize: 18,
    marginVertical: 16,
  },
  box: {
    width: 160,
    height: 160,
    borderRadius: 16,
    backgroundColor: COLORS.PURPLE,
  },
});

Copilot AI review requested due to automatic review settings July 14, 2026 15:45

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a crash when updating a SharedValue-backed enabled config in the v3 gesture API by ensuring runOnJS is invoked on the UI runtime (instead of being created on JS and then executed on UI), aligning with Reanimated/Worklets execution constraints.

Changes:

  • Updates useJSResponderHandler to wrap the JS-side notifier via runOnJS inside a UI worklet before registering SharedValue listeners.
  • Adjusts the Reanimated wrapper type to define runOnJS as a function property type, enabling safe destructuring and usage in the hook.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
packages/react-native-gesture-handler/src/v3/hooks/useJSResponderHandler.ts Moves runOnJS invocation into the UI worklet to prevent “Remote Function” synchronous call crashes when SharedValue changes.
packages/react-native-gesture-handler/src/handlers/gestures/reanimatedWrapper.ts Updates TypeScript typing for runOnJS to a property function type to support destructuring (const { runOnJS } = reanimated).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@m-bert
m-bert requested review from coado and j-piasecki July 14, 2026 15:48
Comment on lines +79 to +81
runOnJS: <A extends unknown[], R>(
fn: (...args: A) => R
): (...args: Parameters<typeof fn>) => void;
) => (...args: Parameters<typeof fn>) => void;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why change it to an arrow function?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed it to property so it can be destructured with { runOnJS } = reanimated

@m-bert
m-bert merged commit fb1089b into main Jul 15, 2026
4 checks passed
@m-bert
m-bert deleted the @mbert/shared-value-crash branch July 15, 2026 07:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants