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

useAnimatedSensor | TypeError: Cannot assign to read-only property 'sensor' fixed. #5537

Closed
wants to merge 3 commits into from

Conversation

talut
Copy link

@talut talut commented Dec 29, 2023

TypeError: Cannot assign to read-only property 'sensor'

Summary

This pull request aims to resolve the issue related to the TypeError: Cannot assign to read-only property 'sensor'. When attempting to modify a read-only property. In this case, the issue arises from reassigning ref.current.sensor within the useRef hook.

While the object returned by useRef is mutable, modifying a read-only property within this object, as done with ref.current.sensor, leads to the error in question.

In the current implementation, ref.current.sensor is initially set with the function initializeSensor(sensorType, config) and is later reassigned in the useEffect hook. It is this reassignment that triggers the error.

To fix this issue, I suggest a code restructuring to avoid the direct reassignment of the sensor property. Instead, we can create a new object for ref.current each time an update is needed. This approach sidesteps the limitations of the read-only property while retaining the intended functionality.

Test plan

yarn add react-native-reanimated
import { SensorType, useAnimatedSensor } from 'react-native-reanimated';
import { View, Button, StyleSheet } from 'react-native';

const SensorTest = () => {
  const [state, setState] = React.useState(0);
  /*
   * Issue:  TypeError: Cannot assign to read-only property 'sensor'
   *
   * Why: This issuse happening while we setting custom userConfig
   * Example: { interval: 10 }
   */
  const animatedSensor = useAnimatedSensor(SensorType.GYROSCOPE, {
    interval: 10,
  });

 useDerivedValue(() => {
    const x = animatedSensor.sensor.value.x;
    const y = animatedSensor.sensor.value.y;

    console.log('x', x);
    console.log('y', y);
  }, [animatedSensor.sensor.value.x, animatedSensor.sensor.value.y]);

  return (
    <View style={styles.container}>
      <Button title="Re-render" onPress={() => setState(state + 1)} />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
  },
});

TypeError: Cannot assign to read-only property 'sensor'
@talut talut marked this pull request as ready for review December 29, 2023 21:05
@talut talut changed the title useRef value reassign issue fixed. useAnimatedSensor | TypeError: Cannot assign to read-only property 'sensor' fixed. Dec 29, 2023
@piaskowyk piaskowyk self-requested a review January 2, 2024 09:11
@tjzel
Copy link
Collaborator

tjzel commented Jan 2, 2024

Hi @talut, thanks for submitting the PR!

I cannot recreate the issue you are trying to fix however. When I'm trying to use the code snippet you posted on the main branch I'm not getting any errors. Am I missing something?

@tjzel
Copy link
Collaborator

tjzel commented Jan 2, 2024

Oh I see, I found #5538 and it happens on re-render. I updated your snippet accordingly.

Copy link
Collaborator

@tjzel tjzel left a comment

Choose a reason for hiding this comment

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

What concerns me here is the fact that with these changes we are no longer returning a stable reference. This is potentially a breaking change.

Maybe we should instead re-work the mechanism due to which this object is getting frozen in the first place, I'll make a PoC of this.

cc @piaskowyk

@tjzel
Copy link
Collaborator

tjzel commented Jan 2, 2024

I opened an alternate pull request to this one. We have to think which one do we want to apply here.

Keep in mind that the problem arises only because return value of useAnimatedSensor is not accessed granularly enough by you (it's not your fault however, since we haven't put any information about it in general). If you instead did:

  const { sensor } = useAnimatedSensor(SensorType.GYROSCOPE, {
    interval: 10,
  });

 useDerivedValue(() => {
    const x = sensor.value.x;
    const y = sensor.value.y;

    console.log('x', x);
    console.log('y', y);
  }); // No need to specify dependencies when Reanimated Babel plugin isn't disabled.

Then everything would be fine.

@talut
Copy link
Author

talut commented Jan 3, 2024

Hey @tjzel thanks for the updates.

You're right my solution returns an unstable reference.

I opened an alternate pull request to this one. We have to think which one do we want to apply here.

Keep in mind that the problem arises only because return value of useAnimatedSensor is not accessed granularly enough by you (it's not your fault however, since we haven't put any information about it in general). If you instead did:

  const { sensor } = useAnimatedSensor(SensorType.GYROSCOPE, {
    interval: 10,
  });

 useDerivedValue(() => {
    const x = sensor.value.x;
    const y = sensor.value.y;

    console.log('x', x);
    console.log('y', y);
  }); // No need to specify dependencies when Reanimated Babel plugin isn't disabled.

Then everything would be fine.

I'll try this one.

Thanks.

@tjzel
Copy link
Collaborator

tjzel commented Feb 12, 2024

Hi @talut, after a debate we decided to actually use a solution very similar to yours, but with added memoization in #5646. I hope you don't mind it, since you were kind-of first here.

@tjzel tjzel closed this Feb 12, 2024
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.

2 participants