React-native-reanimated: Passing a sharedValue as props to a component

Created on 4 Nov 2020  路  12Comments  路  Source: software-mansion/react-native-reanimated

Description

Basically I created a sharedValue and I want to use it in a child component.
Is there a way to do that?

Code

const App = () => {
    const translateX = useSharedValue(0)

    const gestureHandler = useAnimatedGestureHandler({
        // ...
    })

    const animatedStyles = useAnimatedStyle(() => {
        return {
            transform: [{ translateX: translateX.value }]
        }
    })

    return (
        <View style={styles.container}>
            <PanGestureHandler onGestureEvent={gestureHandler}>
                <Animated.View style={[styles.box, animatedStyles]}>
                    <View style={styles.mainOption}>
                        <Text style={styles.mainContent}>Swipe to remove</Text>
                    </View>

                    <Action x={Math.abs(translateX.value)} />
                </Animated.View>
            </PanGestureHandler>
        </View >
    )
}


const Action = ({ x }) => {
    const size = useSharedValue(x < height ? x : x + (x - height))
    // ...
}
鉂換uestion 馃彔 Reanimated2

Most helpful comment

Instead of this

   const x = useSharedValue(0)

   useDerivedValue(() => {
      const formatedValue = Math.abs(props.x.value)
      x.value = formatedValue
   })

You should do this:

   const x = useDerivedValue(() => {
      const formatedValue = Math.abs(props.x.value)
      return formatedValue;
   })

useDerivedValue will be executed each time props.x.value has changed. It will result in the change of x.value. So no, x itself won't be recreated, but the .value of it will be the result of useDerivedValue's callback.

Moving to the next part.

if you need the shared value which depends on some other values, you again need to use useDerivedValue. So this

   const size = useSharedValue(
      x.value < height ?
         x.value :
         x.value + (x.value - height)
   )

   const translateX = useSharedValue(
      x.value < height ?
         0 :
         (x.value - height) / -2
   )

should be replaced with useDerivedValue

   const size = useDerivedValue(() =>
      x.value < height ?
         x.value :
         x.value + (x.value - height)
   )

   const translateX = useDerivedValue(() =>
      x.value < height ?
         0 :
         (x.value - height) / -2
   )

And the final part.

Interpolate - is just a function that returns a value. Only the time it's executed. In order for it to return interpolated opacity - you need to use it inside the useAnimatedStyle like so

   const textStyles = useAnimatedStyle(() => {
     const opacity = interpolate(
       size.value,
       [height - 5, height + 5],
       [0, 1]
     );

      return {
         opacity: opacity
      }
   })

In this useAniamtedStyle, we access size.value so it subscribes for its changes. And now each time the size changes - we rerun the callback. So that interpolation function will be re-executed too. And will return a new value based on the current size.value.

All 12 comments

Pass the shared value as is (not the .value thing) and use useDerivedValue to create a shared value based on that value.

Pass the shared value as is (not the .value thing) and use useDerivedValue to create a shared value based on that value.

I tried something like that, but didn't work

const Action = props => {
    const x = useSharedValue(0)

    useDerivedValue(() => {
        const formatedValue = Math.abs(props.x.value)
        x.value = formatedValue
    })
    // ...
}

The solution that I found is using a useless state to force re-render the component, then I get the new values

const Action = props => {
    const [_, setState] = useState(0)

    const x = useDerivedValue(() => {
        const formatedValue = Math.abs(props.x.value)
        setState(formatedValue)
        return formatedValue
    })
    // ...
}

But it appears to be executed in JS thread instead the UI.
Do you have any suggestions?

in order to pass any value to component, you should use useAnimatedStyle. So just use x in there.

in order to pass any value to component, you should use useAnimatedStyle. So just use x in there.

Yes, but about the state? You have another solution?

What do you need state here for?

What do you need state here for?

As I said, with this code I only get the value of the first render

 const x = useSharedValue(0)

    useDerivedValue(() => {
        const formatedValue = Math.abs(props.x.value)
        x.value = formatedValue
    })

The reason of the state is force an update, then I get the new value (props).
Do you have an example passing a sharedValue as props?

useDerivedValue call returns a shared value which will be updated each time the shared value you used from props is updated. you don't need to have another one.

Also, why do you need your component to rerender?

useDerivedValue call returns a shared value which will be updated each time the shared value you used from props is updated. you don't need to have another one.

Also, why do you need your component to rerender?

I'm using a state because useDerivedValue is not updating.
If I print the value inside useDerivedValue its correct, but outside it doesn't change.

Could you please post a real code here? Unfortunately, I can't understand your intend by the extracted snippets you provided.

Could you please post a real code here? Unfortunately, I can't understand your intend by the extracted snippets you provided.

Sure!

Instead of this

   const x = useSharedValue(0)

   useDerivedValue(() => {
      const formatedValue = Math.abs(props.x.value)
      x.value = formatedValue
   })

You should do this:

   const x = useDerivedValue(() => {
      const formatedValue = Math.abs(props.x.value)
      return formatedValue;
   })

useDerivedValue will be executed each time props.x.value has changed. It will result in the change of x.value. So no, x itself won't be recreated, but the .value of it will be the result of useDerivedValue's callback.

Moving to the next part.

if you need the shared value which depends on some other values, you again need to use useDerivedValue. So this

   const size = useSharedValue(
      x.value < height ?
         x.value :
         x.value + (x.value - height)
   )

   const translateX = useSharedValue(
      x.value < height ?
         0 :
         (x.value - height) / -2
   )

should be replaced with useDerivedValue

   const size = useDerivedValue(() =>
      x.value < height ?
         x.value :
         x.value + (x.value - height)
   )

   const translateX = useDerivedValue(() =>
      x.value < height ?
         0 :
         (x.value - height) / -2
   )

And the final part.

Interpolate - is just a function that returns a value. Only the time it's executed. In order for it to return interpolated opacity - you need to use it inside the useAnimatedStyle like so

   const textStyles = useAnimatedStyle(() => {
     const opacity = interpolate(
       size.value,
       [height - 5, height + 5],
       [0, 1]
     );

      return {
         opacity: opacity
      }
   })

In this useAniamtedStyle, we access size.value so it subscribes for its changes. And now each time the size changes - we rerun the callback. So that interpolation function will be re-executed too. And will return a new value based on the current size.value.

Nice! It works, thank you very much.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ShaMan123 picture ShaMan123  路  3Comments

robertgonzales picture robertgonzales  路  3Comments

mrousavy picture mrousavy  路  3Comments

sa8ab picture sa8ab  路  3Comments

hosseinmd picture hosseinmd  路  3Comments