使用React钩子初始化第三方库

时间:2020-04-06 18:42:41

标签: reactjs react-hooks

我想在使用React钩子挂载某个组件时初始化Swiper实例。调整大小后,我想根据视口宽度销毁或更新Swiper实例。

我正在使用useEffect钩子初始化插件,在其中我调用存储为const的函数。

const MyComponent = () => {
  const [swiper, setSwiper] = useSate(null);
  const element = useRef(null);

  const initSwiper = useCallback(() => {
    // swiper is always null here so I can't destroy the instance
    if (MediaQuery.is('large up') && swiper !== null) {
      return setSwiper(swiper.destroy());
    }

    if (MediaQuery.is('small up')) {
      const currentSwiper = new Swiper(element.current, swiperSettings);
      currentSwiper.init();

      return setSwiper(currentSwiper);
    }
  }, [swiper, swiperSettings]);

  useEffect(() => {
    initSwiper();
    window.addEventListener('resize', initSwiper);

    return () => {
      window.removeEventListener('resize', initSwiper);
    }
  }, []);

  return (
    <div ref={element}>...</div>
}

我想知道初始化后如何访问Swiper实例。我应该使用ref吗?我不太确定最好的方法是什么。

1 个答案:

答案 0 :(得分:2)

您实际上不需要此处的状态。由于useEffect()回调是一个闭包,并且您没有在闭包外使用swiper,因此请创建一个变量(let swiper)并分配Swiper的当前实例到变量。您还应该在闭包内部声明initSwiper,由于useEffect()块仅在init上运行,因此您不需要(实际上也不能)用useEffect()来包装它。

注意swiperSettings不是来自道具或状态,因此useEffect()块并不依赖于它们。如果您需要通过props进行更改,请通过参考传递它们。

const MyComponent = () => {
  const element = useRef(null);

  useEffect(() => {
    let swiper = null;

    const initSwiper = () => {
      if (MediaQuery.is('large up') && swiper !== null) {
        swiper = swiper.destroy();
      } else if (MediaQuery.is('small up')) {
        // swiper.destroy(); // should probably start by destroying the old swiper
        swiper = new Swiper(element.current, swiperSettings);
        swiper.init();
      }
    };

    window.addEventListener('resize', initSwiper);

    return () => {
      window.removeEventListener('resize', initSwiper);
    }
  }, []);

  return (
    <div ref={element}>...</div>
  );
};

并用作自定义钩子(如suggest by @PatrickRoberts):

const useSwiper = () => {
  const element = useRef(null);

  useEffect(() => {
    let swiper = null;

    const initSwiper = () => {
      if (MediaQuery.is('large up') && swiper !== null) {
        swiper = swiper.destroy();
      } else if (MediaQuery.is('small up')) {
        // swiper.destroy(); // should probably start by destroying the old swiper
        swiper = new Swiper(element.current, swiperSettings);
        swiper.init();
      }
    };

    window.addEventListener('resize', initSwiper);

    return () => {
      window.removeEventListener('resize', initSwiper);
    }
  }, []);

  return element;
};

const MyComponent = () => (
  <div ref={useSwiper()} />
);