software-mansion / react-native-reanimated

React Native's Animated library reimplemented
https://docs.swmansion.com/react-native-reanimated/
MIT License
9.05k stars 1.31k forks source link

Cannot add new property '__reanimatedHostObjectRef' #1517

Closed rpavlovs closed 3 years ago

rpavlovs commented 3 years ago

Description

I can't use an array of objects coming in through a prop inside worklets. A prop with a simple value like a number works fine. Also making a deep copy with JSON.parse(JSON.stringify(props.items)) solves the problem.

Looks like Reanimated tries to add a property on an immutable prop object and fails.

Steps to reproduce

type Props = { 
  items: Item[]
}
const MyComponent = ({ items }: Props) => {

  const foo = () => {
    'worklet'
    const item = items[0] // <-- this line causes the error
  }

  return ...
}

Expected behavior

I should be able to use any type of props in worklets

Actual behavior

Cannot add new property '__reanimatedHostObjectRef'

Package versions

github-actions[bot] commented 3 years ago

Issue validator - update # 4

Hello! Congratulations! Your issue passed the validator! Thank you!

karol-bisztyga commented 3 years ago

React Native Reanimated: installed from #1469

I don't think we should handle problems that come from unmerged changes. If you have issues with the code from that PR, please mention them there. Once it's merged and the problem persists, please reopne this issue or open the new one. Thank you 🙏

mrousavy commented 3 years ago

@rpavlovs are you still experiencing this issue? Can you confirm that it actually does work with JSC, but doesn't work with Hermes?

rpavlovs commented 3 years ago

Hey @mrousavy, it's NOT certain that this is coming from your PR.

I haven't tried Reanimated 2 with JSC at all since logs are not usable with out setup. I've also haven't tried it on 0.64.rc-2 which I believe has an updated version of Hermes - so might potentially affect this as well.

You can check if this is still an issue by having a deeply nested object coming from props, that later gets mutated inside a worklet.

rassemdev commented 2 years ago

I also having this issue, when i am trying to console.log(listRef) ref of a listview.

baronha commented 2 years ago

I also got the same error when using react-native-reanimated-carousel.

braandl commented 2 years ago

I have made the following experience, but I can not say for sure yet if it is directly related to RA2:

When you send an Object that is used within RA2 to a native Module, it will crash, emitting this exact error. Once you deepcopy the Object before sending it to the native module, it will not and work as expected.

Tested this with RA2.4.0

dohooo commented 2 years ago

I have made the following experience, but I can not say for sure yet if it is directly related to RA2:

When you send an Object that is used within RA2 to a native Module, it will crash, emitting this exact error.

Once you deepcopy the Object before sending it to the native module, it will not and work as expected.

Tested this with RA2.4.0

Cool, Maybe you can provide a minimal reproducible repository.

jzxchiang1 commented 2 years ago

I just got this error with react-native-bottom-sheet on react-native-v8:

Error: TypeError: Cannot assign to property '__reanimatedHostObjectRef' on HostObject with default setter
This error is located at:
    in BottomSheet (created by BottomSheet)
    in PortalHost (at PortalProvider.tsx:13)
    in PortalProvider (at BottomSheetModalProvider.tsx:190)
    in BottomSheetModalProviderWrapper (at App.tsx:99)
    in AuthProvider (at App.tsx:98)
    in RNCSafeAreaProvider (at SafeAreaContext.tsx:76)
    in SafeAreaProvider (at App.tsx:97)
    in GestureHandlerRootView (at GestureHandlerRootView.android.tsx:26)
    in GestureHandlerRootView (at App.tsx:96)
    in App (at renderApplication.js:47)
    in RCTView (at View.js:34)
    in View (at AppContainer.js:107)
    in RCTView (at View.js:34)
    in View (at AppContainer.js:134)
    in AppContainer (at renderApplication.js:40), js engine: v8

I'm on reanimated v2.2.2.

braandl commented 2 years ago

I currently do not have too much time, I'll try to provide one asap.

yairopro commented 2 years ago

@karol-bisztyga @dohooo @braandl @rpavlovs

Here's a repo reproducing the bug: https://github.com/yairopro/reanimated-2-playground It's a fork from the playground.

https://github.com/yairopro/reanimated-2-playground/blob/ed71b4ebb75e32e9e6ef8b0f5b468af93c7ec20d/Screen.js#L19

I may be wrong but the bug seems to come from trying to access freezed objects from inside worklet. And components' props (unless copied) are freezed by React.

⚠️ The bug doesn't appears in debug mode.

braandl commented 2 years ago

@yairopro Thank you very much! you might me right with the freeze-assumption, or it is some other assertion made on the objects state. Either way, this ticket should be re-opened.

dohooo commented 2 years ago

@yairopro Cool! Thanks!

thisisgit commented 2 years ago

I had the same issue when trying to assign an object or array of objects from Redux state to a shared value.

e.g. using Redux Toolkit(RTK):

// useSelector hook from RTK
const arrayOfObjects: Test[] = useSelector(selectorReturningTests);
const assignThemToMe = useSharedValue<Test[]>([]);

// Throws above error
assignThemToMe.value = arrayOfObjects;

I tried using mock data and it worked just fine. It only throws error when trying to assign value returned from RTK's selector. While trying to figure out where the problem is coming from, I found this:

a

When an object is assigned to a shared value, that object gets mutated by reanimated and a property called __reanimatedHostObjRef gets added. Same for array of objects, every object in the array gets that property after it is assigned to shared value. And looks like it's being added by this function: https://github.com/software-mansion/react-native-reanimated/blob/45c57a906b1c3881c37f08b09749a9c68faf7ce1/Common/cpp/SharedItems/ShareableValue.cpp#L21-L34 I'm assuming that it's throwing the error because it failed to mutate the object, i.e. failed to add __reanimatedHostObjRef property.

But why this issue only occurs when trying to assign data returned from RTK? I think it's because RTK uses immer internally, which is used to freeze the data. And this is related to https://github.com/software-mansion/react-native-reanimated/issues/1517#issuecomment-1041810730, where it throws the same error when trying to play around with frozen object.

Probably that's why the solution of deep copying the object/array of objects using JSON.parse(JSON.stringify(items)) works. I think it would be better to show more readable error message if this issue doesn't get resolved anytime soon.

dohooo commented 2 years ago

I had the same issue when trying to assign an object or array of objects from Redux state to a shared value.

e.g. using Redux Toolkit(RTK):

// useSelector hook from RTK
const arrayOfObjects: Test[] = useSelector(selectorReturningTests);
const assignThemToMe = useSharedValue<Test[]>([]);

// Throws above error
assignThemToMe.value = arrayOfObjects;

I tried using mock data and it worked just fine. It only throws error when trying to assign value returned from RTK's selector. While trying to figure out where the problem is coming from, I found this: a

When an object is assigned to a shared value, that object gets mutated by reanimated and a property called __reanimatedHostObjRef gets added. Same for array of objects, every object in the array gets that property after it is assigned to shared value. And looks like it's being added by this function:

https://github.com/software-mansion/react-native-reanimated/blob/45c57a906b1c3881c37f08b09749a9c68faf7ce1/Common/cpp/SharedItems/ShareableValue.cpp#L21-L34

I'm assuming that it's throwing the error because it failed to mutate the object, i.e. failed to add __reanimatedHostObjRef property. But why this issue only occurs when trying to assign data returned from RTK? I think it's because RTK uses immer internally, which is used to freeze the data. And this is related to #1517 (comment), where it throws the same error when trying to play around with frozen object.

Probably that's why the solution of deep copying the object/array of objects using JSON.parse(JSON.stringify(items)) works. I think it would be better to show more readable error message if this issue doesn't get resolved anytime soon.

Dude, you're so cool

aphillipo commented 2 years ago

Hello, I was having this issue when using a value generated outside of the component in a useAnimatedStyle declaration e.g.:

const data = [{ id: '1', title: 'Test', backgroundColor: 'transparent' }, { id: '2', title: 'Test another', backgroundColor: '#FF6600' }, ....etc. etc.];

const Component = () => {
    const animatedBackgroundColor = useAnimatedStyle(() => {
        const inputValues = data.map((_, index) => index);
        const outputValues = data.map((item) => item.backgroundColor);

        const backgroundColor = interpolateColor(
          animatedBackgroundIndex.value,
          inputValues,
          outputValues,
        );
        return {
          backgroundColor,
        };
    }, [animatedBackgroundIndex]);

    return <Animated.View style={animatedBackgroundColor}>...etc...</Animated.View>;
};

Now moving the generation of input and output values to the component everything works correctly!

const data = [{ id: '1', title: 'Test', backgroundColor: 'transparent' }, { id: '2', title: 'Test another', backgroundColor: '#FF6600' }, ....etc. etc.];

const Component = () => {
    const inputValues = data.map((_, index) => index);
    const outputValues = data.map((item) => item.backgroundColor);

    const animatedBackgroundColor = useAnimatedStyle(() => {
        const backgroundColor = interpolateColor(
          animatedBackgroundIndex.value,
          inputValues,
          outputValues,
        );
        return {
          backgroundColor,
        };
    }, [animatedBackgroundIndex]);

    return <Animated.View style={animatedBackgroundColor}>...etc...</Animated.View>;
};

Hopefully this helps someone else googling this error as to what is going on. It might be worth considering a more friendly error message for this issue!

alexco2 commented 2 years ago

For me this error happened when I referenced a StyleSheet object in the return object of useAnimatedStyle.

  const SnapAnimation = useAnimatedStyle(() => {
    return {
      ...styles.HeaderStyle, <- Error happened here
      transform: [
        {
          translateY: translateY.value,
        },
      ],
    };
  });
itsramiel commented 2 years ago

For me this error happened when I referenced a StyleSheet object in the return object of useAnimatedStyle.

  const SnapAnimation = useAnimatedStyle(() => {
    return {
      ...styles.HeaderStyle, <- Error happened here
      transform: [
        {
          translateY: translateY.value,
        },
      ],
    };
  });

I am having the same issue, using styles from stylesheet inside usAnimatedStyle recreates the issue