When using animated nodes in functional components or inside custom hooks, simply assigning them to a variable (in every render) seems to work fine, but is there a significant cost or other issue to it?
I started out using useMemo like this, because I thought that would match what I was doing before with class fields:
const saw = useMemo(() => Animated.sub(1, ramp), [ramp]);
But maybe it's not neccessary at all?
I recently experienced huge frame drops in JS due to creating animated nodes in render. I couldn't migrate to hooks, so had to write a custom memoize function. But for function components, I think using useMemo is great
@karlsander did you find out how to organise the code with functional components? I am struggling with the same issue, a simple example of a functional component triggering an animation with the press of a button would be great.
I'm using this kind of _class instance variable_ workaround Dan Abramov suggested:
function useVar(cb) {
const ref = useRef(null);
if (ref.current === null) {
ref.current = cb();
}
return ref.current;
}
const opacity = useVar(() => new Animated.Value(1));
But for everything else which requires some kind of dependencies useMemo works best. And it is definitely necessary to use it because each evaluation of Animated.* goes through the bridge.
yes. useMemo (often with [])has worked out well for me, so I would recomend that
are you guys feeling a bit of delay when implementing heavily coded animations using functional component?
Thanks to this video https://www.youtube.com/watch?v=1Q9efh7OcR8 from William Candillon, I managed to get my head around using the library with functional components. Here is my solution highly inspired from the video.
// ...
import Animated, { Easing } from "react-native-reanimated";
import { runTiming, bInterpolate } from "react-native-redash";
import { useMemoOne } from "use-memo-one";
const {
set,
Value,
Clock,
useCode
};
const MyComponent:React.FC<Props> = ({isVisible, action}) => {
// using useMemoOne from use-memo-one
const { animation, clock } = useMemoOne(
() => ({
animation: new Value(isVisible ? 0 : 1),
clock: new Clock()
}),
[isVisible]
);
useCode(
set(
animation,
// runTiming is a helper from react-native-redash
runTiming(clock, animation, {
toValue: selected ? 1 : 0,
duration: 250,
easing: Easing.inOut(Easing.ease)
})
),
[animation]
);
// interpolated value, bInterpolate is a helper from react-native-redash
const transY = bInterpolate(animation, -20, 0);
return (
<TouchableOpacity onPress={action}>
<Animated.View
style={{ transform: [{ translateY: transY }] }}
>
<Text>I slide down or up based on isVisible value</Text>
</Animated.View>
</TouchableOpacity>
);
}
when isVisible change, the animation is restarted and the animation value get interpolated again in the other direction, from 0 to 1, or 1 to 0 depending on the visibility flag.
I hope this would help people having difficulty with functional component implementation and reanimated.
@alwex What about gesture based animations ? because the state change at the middle of running animations seems to interrupt the animation 馃
or at least in my case 馃槃
before I get to know useMemoOne , I used to define some animation values outside of the component function so they won't get rerender and reset every time state changes
I'm using this kind of _class instance variable_ workaround Dan Abramov suggested:
function useVar(cb) { const ref = useRef(null); if (ref.current === null) { ref.current = cb(); } return ref.current; } const opacity = useVar(() => new Animated.Value(1));But for everything else which requires some kind of dependencies useMemo works best. And it is definitely necessary to use it because each evaluation of Animated.* goes through the bridge.
How are you dealing with TS? The .current here is read-only param
How are you dealing with TS? The .current here is read-only param
For Animated Values only I used to have useAnimatedValue hook:
type Value = string | number | boolean;
export function useAnimatedValue<T extends Value>(value: T) {
return React.useMemo<Animated.Value<T>>(() => {
return new Animated.Value(value);
}, []);
}
If you wish to use ref, just ts-ignore the assignments.
The actual assignment to "current" isn't safe only in AsyncMode. But still, no one knows for sure it.
Most helpful comment
Thanks to this video https://www.youtube.com/watch?v=1Q9efh7OcR8 from William Candillon, I managed to get my head around using the library with functional components. Here is my solution highly inspired from the video.
when
isVisiblechange, the animation is restarted and theanimationvalue get interpolated again in the other direction, from 0 to 1, or 1 to 0 depending on the visibility flag.I hope this would help people having difficulty with functional component implementation and reanimated.