Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Strict mode bug: TypeError: Cannot assign to read-only property 'callbackId' #5525

Closed
osamaqarem opened this issue Dec 25, 2023 · 3 comments
Closed
Labels
Needs review Issue is ready to be reviewed by a maintainer Platform: iOS This issue is specific to iOS Repro provided A reproduction with a snippet of code, snack or repo is provided

Comments

@osamaqarem
Copy link

Description

Specifically when there is a framecallback.setActive invocation within a Gesture callback, the error is thrown

Temporarily removing 'use strict' from the hook fixes the problem:

Steps to reproduce

  const frameCb = useFrameCallback(() => {}, false);

  const panGesture = Gesture.Pan().onStart(() => {
    runOnJS(frameCb.setActive)(true);
  });

  return (
      <GestureDetector gesture={panGesture}>
        <View>
          <Text>Test</Text>
        </View>
      </GestureDetector>
    )

Snack or a link to a repository

https://github.com/osamaqarem/reanimated-strict-mode-bug/blob/main/App.tsx

Reanimated version

3.6.1

React Native version

0.73.1

Platforms

iOS

JavaScript runtime

Hermes

Workflow

React Native

Architecture

Paper (Old Architecture)

Build type

Debug app & dev bundle

Device

iOS simulator

Device model

No response

Acknowledgements

Yes

@osamaqarem osamaqarem added the Needs review Issue is ready to be reviewed by a maintainer label Dec 25, 2023
@github-actions github-actions bot added Platform: iOS This issue is specific to iOS Repro provided A reproduction with a snippet of code, snack or repo is provided labels Dec 25, 2023
@tjzel
Copy link
Collaborator

tjzel commented Dec 28, 2023

Hi @osamaqarem, this is not a bug it's a feature 😄!

What I mean by that is without use strict here you'd get a silent fail here instead of an error. I'm currently investigating it. Thanks for the report1

@tjzel
Copy link
Collaborator

tjzel commented Dec 28, 2023

Actually it seems to be a pretty simple problem. The problem is with passing the whole Frame Object to a worklet.

Why

The way how worklets work is that they copy all of their closure values (except for mutables etc.) to the UI thread from JS thread.

If you look here https://github.com/software-mansion/react-native-reanimated/blob/main/src/reanimated2/shareables.ts#L262
you can see that in dev bundles we freeze the objects that we copy. This is done to avoid situations when user would do:

const a = 1;
  useFrameCallback(() => {
    console.log(a);
  }, true);

And expect the outcome to be different once he changes a on JS thread, that's what Shared Values are for. In your case you have a worklet

const panGesture = Gesture.Pan().onStart(() => {
  // This here is a worklet!
});

To which you are passing whole frameCb (we don't get only the accessed property of an object into the closure, we get the whole object). Because of that useFrameCallback cannot modify its internals anymore.

How to solve

Always pass as granular objects as possible to worklets. Best solutions in this case would be:

  const setFrameCbActive = () => frameCb.setActive(true);

  const panGesture = Gesture.Pan().onStart(() => {
    runOnJS(setFrameCbActive)();
  });

or

  const setFrameCbActive = frameCb.setActive;

  const panGesture = Gesture.Pan().onStart(() => {
    runOnJS(setFrameCbActive)(true);
  });

@tjzel tjzel closed this as completed Dec 28, 2023
@osamaqarem
Copy link
Author

Thanks for the thorough explanation, makes complete sense. It wasn't obvious to me that 'setActive' would be a mutation of the object itself - TIL 💡

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs review Issue is ready to be reviewed by a maintainer Platform: iOS This issue is specific to iOS Repro provided A reproduction with a snippet of code, snack or repo is provided
Projects
None yet
Development

No branches or pull requests

2 participants