react-native-reanimated: "Attempting to assign to readonly property" error when using SharedValue across Runtimes (VisionCamera) (interpolateColor: `getInterpolateCacheRGBA`)

Description

Iā€™m using this hook:

export function useAnimatedColor(
  color: Reanimated.SharedValue<string>,
): Readonly<Reanimated.SharedValue<string | number>> {
  const animation = useSharedValue(0);
  const colorFrom = useSharedValue(DEFAULT_COLOR);
  const colorTo = useSharedValue(color.value);

  useAnimatedReaction(
    () => color.value,
    (newColor, prevColor) => {
      animation.value = 0;
      colorFrom.value = prevColor ?? DEFAULT_COLOR;
      colorTo.value = newColor;
      animation.value = withTiming(1, {
        duration: 150,
        easing: Easing.linear,
      });
      console.log(`Animating from ${prevColor} -> ${newColor}`);
    },
  );

  // TODO: Using colorFrom and colorTo in here raises "Attempting to assign to readonly property" error...
  return useDerivedValue(() =>
    interpolateColor(animation.value, [0, 1], [colorFrom.value, colorTo.value]),
  );
}

which results in this error being thrown:

Expected behavior

I expect it to interpolate correctly

Actual behavior & steps to reproduce

It crashes

Snack or minimal code example

https://github.com/mrousavy/Colorwaver (this code throws the error. the passed in SharedValue is being assigned here)

Package versions

  • React Native: 0.65.1
  • React Native Reanimated: 2.3.0-alpha.2
  • NodeJS: 14
  • Xcode: /
  • Java & Gradle: /

Affected platforms

  • Android (not tested)
  • iOS
  • Web (not tested)

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Reactions: 8
  • Comments: 17 (5 by maintainers)

Commits related to this issue

Most upvoted comments

This is fixed with reanimated 2.2.4 btw, which also works with rn 0.66.0

(Or this issue was never introduced in that minor version to begin with šŸ˜… )

Yep, suspicion confirmed. If I remove the caching completely, everything runs smoothly:

 const getInterpolateCacheRGBA = ( 
   colors: readonly (string | number)[] 
 ): InterpolateCacheRGBA => { 
   'worklet'; 
   const hash = colors.join(''); 
   const cache = interpolateCacheRGBA[hash]; 
-  if (cache !== undefined) { 
-    return cache; 
-  } 
  
   const r = []; 
   const g = []; 
   const b = []; 
   const a = []; 
   for (let i = 0; i < colors.length; ++i) { 
     const color = colors[i]; 
     const proocessedColor = processColor(color); 
     if (proocessedColor) { 
       r.push(red(proocessedColor)); 
       g.push(green(proocessedColor)); 
       b.push(blue(proocessedColor)); 
       a.push(opacity(proocessedColor)); 
     } 
   } 
   const newCache = { r, g, b, a }; 
-  const overrideHash = hashOrderRGBA[curentHashIndexRGBA]; 
-  if (overrideHash) { 
-    delete interpolateCacheRGBA[overrideHash]; 
-  } 
-  interpolateCacheRGBA[hash] = newCache; 
-  hashOrderRGBA[curentHashIndexRGBA] = hash; 
-  curentHashIndexRGBA = (curentHashIndexRGBA + 1) % BUFFER_SIZE; 
   return newCache; 
 }; 

I got the same error on iOS using react-native-reanimated@2.3.0-beta.3 and react-native@0.66.1.

I got rid of the error by enabling hermes in the Podfile and running npx pod-install