SwiperJS在React(NextJS)中双向控制失效并触发TypeError报错
SwiperJS React双向控制报错及多Swiper联动解决方案
一、解决"TypeError: Cannot read properties of undefined (reading 'length')"报错
这个错误的核心原因是Swiper实例未完成初始化就被传入controller属性,在NextJS的SSR环境下,服务端渲染阶段无法生成Swiper实例,直接引用ref会拿到undefined,进而触发读取length的错误。
修复方案:
- 使用
useState存储初始化后的Swiper实例,避免直接引用未就绪的ref - 通过Swiper的
onInit事件捕获实例,确保实例就绪后再传递给controller - 可选:对Swiper组件做SSR禁用处理,彻底规避服务端渲染时的实例缺失问题
示例代码:
import { useRef, useState } from 'react'; import { Swiper, SwiperSlide } from 'swiper/react'; import 'swiper/css'; // 若SSR环境问题仍存在,可改用动态导入禁用SSR // import dynamic from 'next/dynamic'; // const Swiper = dynamic(() => import('swiper/react').then(mod => mod.Swiper), { ssr: false }); // const SwiperSlide = dynamic(() => import('swiper/react').then(mod => mod.SwiperSlide), { ssr: false }); export default function DualSwiper() { const firstRef = useRef(null); const secondRef = useRef(null); const [firstSwiper, setFirstSwiper] = useState(null); const [secondSwiper, setSecondSwiper] = useState(null); // 通过onInit事件捕获初始化完成的实例 const handleFirstInit = (swiper) => setFirstSwiper(swiper); const handleSecondInit = (swiper) => setSecondSwiper(swiper); return ( <> <Swiper ref={firstRef} controller={{ control: secondSwiper }} onInit={handleFirstInit} slidesPerView={1} spaceBetween={10} > <SwiperSlide>滑块1</SwiperSlide> <SwiperSlide>滑块2</SwiperSlide> <SwiperSlide>滑块3</SwiperSlide> </Swiper> <Swiper ref={secondRef} controller={{ control: firstSwiper }} onInit={handleSecondInit} slidesPerView={1} spaceBetween={10} style={{ marginTop: '20px' }} > <SwiperSlide>滑块A</SwiperSlide> <SwiperSlide>滑块B</SwiperSlide> <SwiperSlide>滑块C</SwiperSlide> </Swiper> </> ); }
二、实现4个Swiper的联动控制
完全可以通过相同逻辑实现多Swiper联动,核心是将每个Swiper的实例存储后,在controller.control中传入除自身外的所有其他Swiper实例数组。
示例代码:
import { useRef, useState } from 'react'; import { Swiper, SwiperSlide } from 'swiper/react'; import 'swiper/css'; export default function MultiSwiper() { // 创建4个ref用于绑定每个Swiper组件 const swiperRefs = Array.from({ length: 4 }, () => useRef(null)); // 存储所有初始化完成的Swiper实例 const [swiperInstances, setSwiperInstances] = useState([]); // 单个Swiper初始化时更新实例数组 const handleSwiperInit = (swiper, index) => { setSwiperInstances(prev => { const newInstances = [...prev]; newInstances[index] = swiper; return newInstances; }); }; return ( <div> {swiperRefs.map((ref, index) => ( <Swiper key={index} ref={ref} // 控制除当前Swiper外的所有其他实例 controller={{ control: swiperInstances.filter((_, i) => i !== index) }} onInit={(swiper) => handleSwiperInit(swiper, index)} slidesPerView={1} spaceBetween={10} style={{ marginBottom: '20px' }} > {[1, 2, 3].map(num => ( <SwiperSlide key={num}> 轮播{index + 1} - 滑块{num} </SwiperSlide> ))} </Swiper> ))} </div> ); }
内容的提问来源于stack exchange,提问作者Skythz
相关产品推荐
相关产品推荐

