在 useImperativeHandle 函数中未定义 let 变量

问题描述

我在 React Native (Expo) 下的 .web.js 文件中使用 lottie-web 包。

我的问题是在 useImperativeHandle 中的函数中未定义 let 变量 anim。在 useEffect 中,动画效果非常好。例如,如果我在 useEffect 初始化后立即访问 anim.play() ,它会起作用。但是在命令式的 play() 函数中它不起作用。

在我的父组件中,我使用 useRef 创建了一个 ref 并将该 ref 传递给组件

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);
  },}));

解决方法

这是因为 React 在 useImperativeHandle 中创建 API 函数时不知道 anim 是什么(由于闭包和反应更新策略不会通过改变变量来触发任何更新)。有一些方法可以解决这个问题,毕竟这涉及到个人意见该怎么做,我会使用这样的方法,效果最好 对我来说。

添加 GetApi 函数

// 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
});

以状态存储动画

将动画存储在仅用于首次渲染的状态中,并在 getApi useEffect 的依赖项数组中使用

const [anim,setAnim] = React.useState(null);

React.useEffect(() => {
  // initialization part
},[]);

React.useImperativeHandle(ref,getAPI(anim),[anim]);