Next.js集成Swiper断点配置引发Hydration不匹配错误的解决方法
解决Next.js中Swiper断点导致的Hydration不匹配问题
以下是实现Swiper轮播的代码:
const breakpoints = { 0: { slidesPerView: 1, }, 576: { slidesPerView: 1, }, 768: { slidesPerView: 2, }, 992: { slidesPerView: 3, }, 1199: { slidesPerView: 4, }, }
<Swiper modules={[Navigation]} spaceBetween={30} slidesPerView={4} loop={true} navigation={{ nextEl: sliderNextEl.current, prevEl: sliderPrevEl.current, }} breakpoints={breakpoints} className="sg-portfolio-active swiper-container" > <SwiperSlide>Hello 1</SwiperSlide> <SwiperSlide>Hello 2</SwiperSlide> <SwiperSlide>Hello 3</SwiperSlide> </Swiper>
在桌面模式(>=1199px)下运行正常,但切换到移动端视图并刷新页面时,Next.js抛出如下错误:
Prop `data-swiper-slide-index` did not match. Server: "0" Client: "3" Error: Hydration failed because the initial UI does not match what was rendered on the server.
注释掉Swiper组件中的breakpoints={breakpoints}配置后问题消失,尝试用state存储breakpoints传入Swiper未生效。
环境版本:
swiper: ^8.4.5 NextJs: 13.1.1 ReactJs: 18.2.0
解决方法
1. 仅在客户端渲染Swiper组件
Next.js服务端渲染时无法获取客户端窗口尺寸,导致服务端与客户端根据断点计算的幻灯片数量不一致,直接禁用Swiper组件的SSR:
import dynamic from 'next/dynamic'; // 动态导入Swiper和SwiperSlide,禁用SSR const Swiper = dynamic(() => import('swiper/react').then(mod => mod.Swiper), { ssr: false, }); const SwiperSlide = dynamic(() => import('swiper/react').then(mod => mod.SwiperSlide), { ssr: false, });
之后正常使用组件即可,组件仅在客户端渲染,避免服务端与客户端DOM不匹配。
2. 客户端挂载后再设置断点
如果需要保留SSR,可在组件挂载后(仅客户端环境)再设置断点,确保服务端渲染时使用默认配置:
import { useState, useEffect } from 'react'; export default function YourComponent() { const [clientBreakpoints, setClientBreakpoints] = useState(null); useEffect(() => { // 仅在客户端设置断点 setClientBreakpoints({ 0: { slidesPerView: 1 }, 576: { slidesPerView: 1 }, 768: { slidesPerView: 2 }, 992: { slidesPerView: 3 }, 1199: { slidesPerView: 4 }, }); }, []); return ( <Swiper modules={[Navigation]} spaceBetween={30} slidesPerView={4} loop={true} navigation={{ nextEl: sliderNextEl.current, prevEl: sliderPrevEl.current, }} breakpoints={clientBreakpoints} className="sg-portfolio-active swiper-container" > <SwiperSlide>Hello 1</SwiperSlide> <SwiperSlide>Hello 2</SwiperSlide> <SwiperSlide>Hello 3</SwiperSlide> </Swiper> ); }
服务端渲染时breakpoints为null,Swiper使用默认的slidesPerView=4,客户端挂载后再应用断点配置,仅会触发一次重渲染,不会导致Hydration错误。
3. 延迟开启loop模式
loop模式下Swiper会复制幻灯片,服务端与客户端的幻灯片数量计算差异会导致索引不匹配,可在客户端挂载后再开启loop:
import { useState, useEffect } from 'react'; export default function YourComponent() { const [isClient, setIsClient] = useState(false); const [clientBreakpoints, setClientBreakpoints] = useState(null); useEffect(() => { setIsClient(true); setClientBreakpoints({ 0: { slidesPerView: 1 }, 576: { slidesPerView: 1 }, 768: { slidesPerView: 2 }, 992: { slidesPerView: 3 }, 1199: { slidesPerView: 4 }, }); }, []); return ( <Swiper modules={[Navigation]} spaceBetween={30} slidesPerView={4} loop={isClient} navigation={{ nextEl: sliderNextEl.current, prevEl: sliderPrevEl.current, }} breakpoints={clientBreakpoints} className="sg-portfolio-active swiper-container" > <SwiperSlide>Hello 1</SwiperSlide> <SwiperSlide>Hello 2</SwiperSlide> <SwiperSlide>Hello 3</SwiperSlide> </Swiper> ); }
结合断点的客户端设置,彻底避免服务端与客户端的渲染差异。
内容的提问来源于stack exchange,提问作者Tajmirul Islam
相关产品推荐
相关产品推荐

