software-mansion / react-native-reanimated

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

Should useDerivedValue cause a rerender? #1487

Closed doylemark closed 3 years ago

doylemark commented 3 years ago

Description

If I format a date on the ui thread like so..

const date = useDerivedValue(() => {
    const d = interpolate(translation.x.value, [0, width], [MIN, MAX]);
    return formatDateOnUI(d);
});

return <Text>{date}</Text>

In this example date will update (can check by logging d before return), however it will not update the UI.. I can hack around this by calling some setState with runOnJS and that triggers a re-render but of course affects fps on the JS thread

Package versions

github-actions[bot] commented 3 years ago

Issue validator - update # 1

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

terrysahaidak commented 3 years ago

if you want something to be updated on UI Thread - you need to pass it as animatedProps.

The React Native Text doesn't support this, but there is a library https://github.com/axelra-ag/react-native-animateable-text

doylemark commented 3 years ago

Hi, I checked out this library too, but found the same problems.. I'm confused if it's a library problem I'm encountering or a bug in my code

const someNum = useDerivedValue(() => {
  const c = interpolate(
    translation.y.value,
    [0, width - 48],
    [data.MIN, data.MAX]
  );

  return c.toFixed();
});

const animatedProps = useAnimatedProps(() => {
  console.log(someNum.value);
  return {
    text: someNum.value,
  };
});

return (
  <View>
    <AnimateableText animatedProps={animatedProps} />
  </View>
)

Here is a GIF of someNum.value being logged from animatedProps however it's not updated either (note the static 1336 in drawer).. The UI will update if I change some state from within useDerivedValue or animatedProps however.

gif

karol-bisztyga commented 3 years ago

You can use Animated.TextInput, disable editing by the user, and append appropriate styles to it, just as a workaround to it, as input text, as far as I remember, supports such updates.

jonsamp commented 3 years ago

I am experiencing the same behavior, where none of the examples I can find work for updating text. I tried the npm package referenced earlier in this thread, and also using Animated.TextInput.

Here's what I'm seeing:

Similar to @doylemark, I can see the result of useDerivedValue() logging to my console, but its value never updates in my UI:

no-update

Here's my code:

const AnimatedTextInput = Animated.createAnimatedComponent(TextInput)

// ...

const stepText = useDerivedValue(() => {
  const sliderRange = SLIDER_WIDTH - KNOB_WIDTH
  const oneStepValue = sliderRange / MAX_RANGE
  const step = Math.ceil(translateX.value / oneStepValue)

  return String(step)
})

const animatedProps = useAnimatedProps(() => {
  console.log(stepText.value)
  return {
    value: stepText.value,  // this doesn't work if I use "text" as the key here either
  }
})

// ...

<AnimatedTextInput
  underlineColorAndroid="transparent"
  editable={false}
  style={{ fontSize: 24 }}
  animatedProps={animatedProps}
/>

I got to this code by following this blog. The examples in that blog do not work for me, however the author of that blog has gifs of the code working, so I suspect it did work. Im running "react-native-reanimated": "^2.0.0-alpha.9.2" in a bare Expo project.

I also made a reproducible demo you can clone and run. It's adds a Slider component to the reanimated playground demo app: https://github.com/jonsamp/reanimated-animatedprops-repro

karol-bisztyga commented 3 years ago

I think .text is a proper approach, but it also would have to be added to NATIVE_THREAD_PROPS_WHITELIST I guess. @doylemark would it suffice as a (let's say) proper way of performing that thing you posted?

karol-bisztyga commented 3 years ago

@jonsamp please check this

jonsamp commented 3 years ago

@karol-bisztyga Thanks, adding this worked:

Animated.addWhitelistedNativeProps({text: true});
wcandillon commented 3 years ago

Thanks gang!

doylemark commented 3 years ago

So can we conclude the described issues were caused by a regression in RC.0 which is now resolved?

wcandillon commented 3 years ago

We can close this issue probably. Or we could close it if you would like Animated.addWhitelistedNativeProps({text: true}); to be done automatically.

doylemark commented 3 years ago

This seems to be resolved so I will close.

anastely commented 3 years ago

@karol-bisztyga Thanks, adding this worked:

Animated.addWhitelistedNativeProps({text: true});

Hey, Where you added it exactly? Can u share final code snippet

jakub-gonet commented 3 years ago

@anastely, you can add it wherever you want, you only want to ensure it runs only once. index.js or App.js or any standalone configuration file that is included there is fine. Using that in a component file (outside of component definition) is also fine but you may prefer a more "global" place to keep your configs in.

karol-bisztyga commented 3 years ago

you only want to ensure it runs only once

I think that does not break a thing, however, it would be inefficient as it overwrites collections on both, js and the native side.

friedebold commented 3 years ago

I am trying to display the number of pixels scrolled solely from the UI thread similar to the examples above. It successfully prints into the console but does not update the AnimatedTextInput props for some reason.

Does anyone have a clue why it does not work? Might using expo be a problem when using createAnimatedComponent()?

ezgif com-gif-maker

My code:

const dimensions = useWindowDimensions()
const AnimatedTextInput = Animated.createAnimatedComponent(TextInput)
Animated.addWhitelistedNativeProps({ text: true })

const y = useSharedValue(0);
const scrollHandler = useAnimatedScrollHandler((e) => y.value = e.contentOffset.y)
const yTxt = useDerivedValue(() => String(y.value))

const animatedProps = useAnimatedProps(() => {
  console.log(yTxt.value)
  return {
    value: yTxt.value,
  }
})

return (
  <View style={{ height: dimensions.height, width: dimensions.width }}>
    <Animated.ScrollView
      onScroll={scrollHandler}
      stickyHeaderIndices={[0]}
      scrollEventThrottle={16}>
      <AnimatedTextInput
        underlineColorAndroid="transparent"
        editable={false}
        animatedProps={animatedProps}
      />
      <Content />
    </Animated.ScrollView>
  </View>
)
Navipro70 commented 2 years ago

@friedebold

const animatedProps = useAnimatedProps(() => {
  console.log(yTxt.value)
  return {
    text: yTxt.value,
  }
})

Your useAnimatedProps func should return {text: ...} instead of {value: ...}

andrewdang17 commented 2 years ago

@friedebold did you end up getting it to work? I am running into this issue as well

friedebold commented 2 years ago

I would use worklets now https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/worklets

TFRadicalImaging commented 1 year ago

Why this is closed?