Open mxmzb opened 2 years ago
It's weird, but can you try to first convert it to a derived value using useDerivedValue()
and then use it as a prop?
This is some internal thing that I also don't quite understand.
I'm not sure how to do that, because useDerivedValue()
returns a readonly value. The following seems not to work, but I cannot animate animatedText
with withTiming
, because it's readonly.
import React from "react";
import AnimateableText from "react-native-animateable-text";
import {
useSharedValue,
useAnimatedProps,
useDerivedValue,
Easing,
withTiming,
} from "react-native-reanimated";
import { SafeAreaView } from "react-native-safe-area-context";
const formatScore = (score = 0) => {
"worklet";
return "" + score.toFixed(0);
};
const AnimateScoreTextValueScreen = () => {
const score = useSharedValue(0);
React.useEffect(() => {
score.value = withTiming(500, {
duration: 1000,
easing: Easing.inOut(Easing.ease),
});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const animatedText = useDerivedValue(() => score.value);
const scoreAnimatedProps = useAnimatedProps(() => ({
text: formatScore(animatedText.value),
}));
return (
<SafeAreaView>
<AnimateableText animatedProps={scoreAnimatedProps} />
</SafeAreaView>
);
};
export default AnimateScoreTextValueScreen;
Try to call formatScore inside the useDerivedValue hook, and then use the return value directly to text inside useAnimatedProps.
Try to call formatScore inside the useDerivedValue hook, and then use the return value directly to text inside useAnimatedProps.
Unfortunately, it doesn't work:
import React from "react";
import AnimateableText from "react-native-animateable-text";
import {
useSharedValue,
useAnimatedProps,
useDerivedValue,
Easing,
withTiming,
} from "react-native-reanimated";
import { SafeAreaView } from "react-native-safe-area-context";
const formatScore = (score = 0) => {
"worklet";
return "" + score.toFixed(0);
};
const AnimateScoreTextValueScreen = () => {
const score = useSharedValue(0);
React.useEffect(() => {
score.value = withTiming(500, {
duration: 1000,
easing: Easing.inOut(Easing.ease),
});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const animatedText = useDerivedValue(() => formatScore(score.value));
// also doesn't work:
// const animatedText = useDerivedValue(() => "" + score.value.toFixed(0));
// const scoreAnimatedProps = useAnimatedProps(() => ({
// text: formatScore(animatedText.value),
// }));
return (
<SafeAreaView>
<AnimateableText
text={animatedText.value}
// animatedProps={scoreAnimatedProps}
/>
</SafeAreaView>
);
};
export default AnimateScoreTextValueScreen;
What if you do it like this?
const progress = useSharedValue(0.5);
const textProps = useAnimatedProps(() => {
return { text: `${(progress.value * 100).toFixed(0)}%` };
}, []);
return (<AnimateableText style={styles.text} animatedProps={textProps} />)
Unfortunately, doesn't work as well (still animating the progress.value
in a useEffect(..., [])
with withTiming
).
Edit: Hmm, at this point, it feels like I'm doing something wrong...
What about:
import React from "react";
import AnimateableText from "react-native-animateable-text";
import {
useSharedValue,
useAnimatedProps,
useDerivedValue,
Easing,
withTiming,
} from "react-native-reanimated";
import { SafeAreaView } from "react-native-safe-area-context";
const formatScore = (score = 0) => {
"worklet";
return "" + score.toFixed(0);
};
const AnimateScoreTextValueScreen = () => {
const score = useSharedValue(0);
React.useEffect(() => {
score.value = withTiming(500, {
duration: 1000,
easing: Easing.inOut(Easing.ease),
});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const animatedText = useDerivedValue(() => formatScore(score.value));
const scoreAnimatedProps = useAnimatedProps(() => ({
text: animatedText.value,
}));
return (
<SafeAreaView>
<AnimateableText animatedProps={scoreAnimatedProps} />
</SafeAreaView>
);
};
export default AnimateScoreTextValueScreen;
I don't know how these rules apply either, it's weird. But the demo code in the README should work, therefore I adjusted your example a bit and this is what I suggest.
Nope, it just stays at 0. Am I missing any steps before maybe? I followed the reanimated installation guide, have the babel plugin, anything else?
The only way this works for me is just by arbitrarily changing the return of the useDerivedValue
hook (e.g.
const animatedText = useDerivedValue(() => "this is some new change" + score.value);
). I've also tried to set random values with a setTimeout
loop, that didn't work either.
@mxmzb It has been a year but I came across this same problem! So I spent my entire day trying a ton of solutions.
Here is what I came up with that works.
const CurrencyDisplay = ({ value: currencySharedValue, ...props }: CurrencyDisplayProps) => {
// NativeBase issue as I like having my style props >:(
// This should be at the top of the file but for whatever reason, it doesn't work like that.
const AnimateableText = Factory(NativeAnimateableText);
const intl = useIntl();
// Have our pseudo value
const animatedValue = useSharedValue('0');
// This isn't a worklet, but it works.
const formatNumber = useCallback((formatValue: number) => {
// Attach formatted number to the above value when ran
animatedValue.value = intl.formatNumber(formatValue, {
style: 'currency',
currency: 'USD',
minimumFractionDigits: 0,
maximumFractionDigits: 0,
});
}, []);
// After one second, start at 0, go to whatever value you set
const animateToValue = useDerivedValue(() =>
withDelay(
1000,
withSequence(
withTiming(0, {
easing: Easing.inOut(Easing.ease),
}),
// Just solved this but wanted to add a decay animation, and decay can't be used for something like this
withSpring(currencySharedValue.value, { damping: 95, stiffness: 1 })
)
)
);
// When values update, update this using the JS thread so we can use intl
useDerivedValue(() => {
runOnJS(formatNumber)(animateToValue.value);
});
const scoreAnimatedProps = useAnimatedProps(() => ({
text: animatedValue.value,
}));
return <AnimateableText animatedProps={scoreAnimatedProps} {...props} />;
};
Let me know if that works or makes sense!
I am trying to animate the text value over time, like this:
With very similar code, I was able to animate paths from
react-native-svg
. Shouldn't this work?PS.: Thank you so much for your efforts and for creating this component, much appreciated!