Open ethanshar opened 2 years ago
I don't think this is a Reanimated issue.
This is how JavaScript works. You're actually calling getInitialValue()
yourself (look at the code again).
I think you're looking for (nevermind, that doesn't seem to exist, you'd need to memoize yourself)useSharedValue(() => getInitialValue())
instead.
See here for a similar discussion about useState
: https://kentcdodds.com/blog/use-state-lazy-initialization-and-function-updates#usestate-lazy-initialization
yeah, as @andreialecu, by calling the function, you are calling it on each render. the behavior is correct.
useState
lets you pass a function and under the hood it only calls it for you once. useSharedValue
doesn't have a lazy API, I believe. Maybe you can do something like this:
const value = useSharedValue(null)
if (value.value === null) {
value.value = getValueLazily()
}
I'm not sure if this is safe for concurrent mode or not. It may be fine.
This issue should be closed though
I would expect useSharedValue
to work similarly to useState
or useRef
.
Creating a variable using one of these hooks preserve its value through renders.
Having to memoize the shared value sound trivial to me, why would anyone don't want to memoize it? Shouldn't it be memoized by the hook internally? Does it make sense for a shared value to reset its value on each render? to me It sounds like a bug.
just to clarify, it has nothing to do with the fact I'm initializing the shared value with getInitialValue()
method.
I could initialize it with a static value, like this const myData = useSharedValue(true)
It would still trigger a reaction (useAnimatedReaction
) on each render.
I could be wrong, but you need to pass a dependency array to useAnimatedReaction
, otherwise it's similar to useEffect
and it runs on every render regardless of using any shared values or not.
You can confirm this by changing the code to:
useAnimatedReaction(() => 0, () => console.log('myData has changed'));
It will log that myData
has changed every time. So this is not related to useSharedValue
Using the following will correctly only log it once:
useAnimatedReaction(() => myData.value,
() => {
console.log('myData has changed');
}, []); // or [myData]
I would agree that the documentation related to useAnimatedReaction
's dependency array argument could be better.
Snack for easy testing: https://snack.expo.dev/KtdoeN4r2
useAnimationReaction
‘s function receives both a new
and old
argument. you can compare these two in the function and only do something if it has changed.
useAnimationReaction
‘s function receives both anew
andold
argument. you can compare these two in the function and only do something if it has changed.
Yes, I'm well aware and that's exactly the problem I'm facing. Because the shared value is being reset on render, I receive a reaction on this change
@ethanshar re-read my message just above, it explains why this happens and has nothing to do with the shared value. There's also a snack you can experiment with.
useAnimatedReaction(() => 0, () => console.log('myData has changed'));
prints the same message
@ethanshar did you find a work around for this? I'm facing the same issue with useSharedValue and useAnimatedStyle
Unfortunately, this issue still exists. Shared value gets reset on every re-render of component!
I had a similar bug (on Android only, not iOS, no idea why) where the initial opacity would stay at 1 instead of 0 even though I wrote useSharedValue(0)
. Replacing it with useAnimatedStyle()
solved it for me.
Explain: Each time component is re-render. sharedValue has not been updated yet. It reset to init value as you mentioned above. So, you can update it after your component done for re-render.
interface Props {
counter: number;
...
};
const Child = ({counter}: Props) => {
const sharedValue = useSharedValue(0);
useEffect(() => {
const timeoutId = setTimeOut(() => { // <= Here is solution for me
sharedValue.value = counter;
}, 0);
return () => clearTimeout(timeoutId);
}, [counter]);
return <View>
<Text>{counter}</Text>
</View>
};
export default memo(Child);
Description
It appears
useSharedValue
reset the value on each render of a component, instead of setting it once with the initial value. I notice this issue https://github.com/software-mansion/react-native-reanimated/issues/1655 but wasn't 100% sure if this is something that was fixed.Expected behavior
useSharedValue
should initialize the value once with provided initial value.Actual behavior & steps to reproduce
Run the snippet below to reproduce
Snack or minimal code example
Package versions
Affected platforms