React-native-reanimated: useSharedValue is not memoized

Created on 29 Sep 2020  路  4Comments  路  Source: software-mansion/react-native-reanimated

From hooks like useState(x) from React, or useValue(x) from Redash, I am used to the behavior that if x changes, the return value of the hook stays the same unless I manipulate the value afterwards (e.g using setState/setValue)

When the x in const val = useDerivedValue(x) changes, I was surprised to see that the Shared Value updates too.

I'm led to believe that this is a bug. Could it be?

Versions

  • React: 16.3
  • React Native: 0.63.2
  • React Native Reanimated: 2.0.0-alpha.7
鉂換uestion 馃彔 Reanimated2 馃 To verify

Most helpful comment

I use this hook as a workaround for now:

export function useSharedValue<T>(value: T, shouldRebuild = false) {
  const ref = useRef<T | null>(null);
  if (ref.current === null || shouldRebuild) {
    ref.current = value;
  }

  return REAuseSharedValue(ref.current);
}

All 4 comments

Repro:

import React, {useState} from 'react';
import {Button, StyleSheet, View} from 'react-native';
import {useSharedValue} from 'react-native-reanimated';

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

export const StartScreen = () => {
    const [x, setX] = useState(0);
    const val = useSharedValue(x);

    console.log(val.value);
    // After pressed the button, the shared value has changed
    // without `val.value = 1` ever being called

    return (
        <View style={styles.centered}>
            <Button title="Press me" onPress={() => setX(1)} />
        </View>
    );
};

I see your point, it is not a bug, just a matter of approach(by saying that I mean we did it that way consciously).

You're right that a result of useState changes only when triggered explicitly.
Adding such functionality is very easy, we could also go for conditional change on rerender. We're going to discuss it, thanks!

I use this hook as a workaround for now:

export function useSharedValue<T>(value: T, shouldRebuild = false) {
  const ref = useRef<T | null>(null);
  if (ref.current === null || shouldRebuild) {
    ref.current = value;
  }

  return REAuseSharedValue(ref.current);
}

Thanks a lot for considering to change it!

What I think would be the advantage of memoizing it is that you can yourself change the shared value in an effect and also wrap it in a withTiming or withSpring function, and with that easily achieve a transition effect when a prop is changing.

@terrysahaidak's workaround works great as well, thanks a lot!

Was this page helpful?
0 / 5 - 0 ratings