Reputation: 472
I want to initialise a Swiper instance when a certain component mounts using React hooks. On resize I want to destroy or update the Swiper instance depending on the viewport width.
I'm initialising the plugin with the useEffect
hook where I'm calling a function stored as a 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>
}
I would like to know how I can access the Swiper instance after initialisation. Should I use a ref
? I'm not really sure what the best way is to handle this.
Upvotes: 1
Views: 1192
Reputation: 192242
You don't actually need state here. Since the useEffect()
callback is a closure, and you don't use swiper
outside of the closure, create a variable (let swiper
), and assign the current instance of Swiper
to the variable. You should also declare initSwiper
inside the closure, and you don't need (and actually can't) to wrap it with useEffect()
since the useEffect()
block only runs on init.
Note: swiperSettings
are not coming from the props or state, so the useEffect()
block is not dependant on them. If you need to change it via props
, pass them via a ref.
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>
);
};
And used as a custom hook (as 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()} />
);
Upvotes: 2