I work with the lottie-web package in a .web.js file under React Native (Expo).
My problem is that the let variable anim is undefined in the functions in useImperativeHandle. In the useEffect anim works wonderfully. For example if I access anim.play() right after the initialize at useEffect it works. But at the play() function in imperative it doesn't work.
At my parent component I create a ref with useRef and pass the ref to the component
const lottieAnim = useRef(null);
--
let anim;
useEffect(() => {
const lottieOptions = {
container: divContainer.current,
renderer: 'svg',
loop,
autoplay,
segments: segments !== false,
animationData,
rendererSettings,
};
anim = lottie.loadAnimation({ ...lottieOptions, ...options });
// anim.play(); works here
if (onAnimationFinish) {
anim.addEventListener('complete', onAnimationFinish);
}
}, []);
useImperativeHandle(ref, () => ({
stop() {
anim.stop();
},
pause() {
anim.pause();
},
play() {
anim.play();
// anim is undefined
},
setSpeed(s) {
anim.setSpeed(s);
},
setDirection(d) {
anim.setDirection(d);
},
playSegments(s) {
anim.playSegments(s);
},
}));
I've created a package for connecting third-party packages to react via useImperativeHandler in an easier way, you might find it useful and easier to use 😊.
react-aptor
That is because React has no clue what anim
is when it creates API functions in useImperativeHandle (duo to closure and react updating strategies that don't trigger any update by mutating a variable). There is some way you can handle this, after all, it comes to personal opinion what to do, I will use something like this which work the best
for me.
// hanlder.js
const stop = anim => anim.stop()
// api.js
const getAPI = anim => () => ({
stop: stop.bind(this, anim),
// or simply
setSpeed: s => anim.setSpeed(s),
// you can mock APIs here if anim is null or throw an Error
});
anim
in a statestore
anim
in the state for the first render only and use it in the dependencies array of getApi useEffect
const [anim, setAnim] = React.useState(null);
React.useEffect(() => {
// initialization part
}, []);
React.useImperativeHandle(ref, getAPI(anim), [anim]);