Next.js13使用tiny-slider-react报window未定义错误的解决方法
问题:Next.js 13中使用tiny-slider-react出现window is not defined错误
我用Next.js 13搭建网站,首页通过tiny-slider-react实现产品轮播组件。已经在carousel.js首行添加'use client'指令,并且通过useEffect判断window对象存在后再渲染TinySlider组件,但每次刷新页面和执行npm run build时都会触发ReferenceError: window is not defined错误。
错误信息
刷新页面时:
- error node_modules\tiny-slider\dist\tiny-slider.js (5:0) @ eval
- error ReferenceError: window is not defined
- at webpack_require (F:\Projects\nexjs\decoz.next\server\webpack-runtime.js:33:42)
执行npm run build时:
- info Collecting page data
- [ ] - info Generating static pages (0/4)ReferenceError: window is not defined
原代码
carousel.js
"use client"; import TinySlider from "tiny-slider-react"; import CarouselItem from "./carousel-item"; import "tiny-slider/dist/tiny-slider.css"; import { useEffect, useState } from "react"; function Carousel(props) { const [mount, setMount] = useState(false); const { children } = props; useEffect(() => { if (typeof window === "object") { setMount(true); } }, [setMount, window]); const settings = { lazyload: true, nav: false, mouseDrag: true, loop: true, items: 1, gutter: 20, controls: false, autoplay: true, autoplayHoverPause: true, autoplayButtonOutput: false, speed: 250, autoplayTimeout: 2500, responsive: { 2048: { items: 10, }, 1920: { items: 4, }, 1728: { items: 4, }, 1440: { items: 4, }, 1280: { items: 4, }, 1194: { items: 4, }, 1114: { items: 4, }, 1180: { items: 4, }, 1104: { items: 4, }, 1024: { items: 4, }, 834: { items: 2, }, 820: { items: 2, }, 800: { items: 2, }, 768: { items: 2, }, }, }; if (mount) { return ( <TinySlider settings={settings} onInit={() => {}}> {props.data.map((item) => ( <CarouselItem key={item.id} data={item} /> ))} </TinySlider> ); } return null; } export default Carousel;
package.json
{ "name": "my-app", "version": "0.1.0", "private": true, "scripts": { "dev": "next dev", "build": "next build", "start": "next start", "lint": "next lint" }, "dependencies": { "aos": "^2.3.4", "eslint": "8.40.0", "eslint-config-next": "13.4.1", "next": "13.4.1", "react": "18.2.0", "react-dom": "18.2.0", "tiny-slider-react": "^0.5.7" } }
解决方案
问题核心:即使添加了'use client',Next.js在构建或服务端渲染阶段仍会执行模块导入逻辑,而tiny-slider的源码直接依赖window对象,导致服务端执行时出错。
1. 动态导入tiny-slider-react并禁用SSR
使用Next.js提供的dynamic函数,仅在客户端环境导入组件,避免服务端执行相关代码:
2. 优化状态初始化与依赖项
- 直接在
useState中判断window是否存在,减少一次无意义的渲染 - 移除
useEffect依赖中的window和setMount(setMount是稳定函数,无需加入依赖,window是全局变量,加入依赖会导致无限循环)
修改后的完整代码
"use client"; import CarouselItem from "./carousel-item"; import "tiny-slider/dist/tiny-slider.css"; import { useEffect, useState } from "react"; import dynamic from 'next/dynamic'; // 动态导入TinySlider,禁用SSR const TinySlider = dynamic(() => import('tiny-slider-react'), { ssr: false, loading: () => null // 加载时显示null,也可以自定义加载组件 }); function Carousel(props) { // 直接初始化mount状态,判断window是否存在 const [mount, setMount] = useState(typeof window !== 'undefined'); useEffect(() => { // 确保客户端挂载后更新状态(可选,保险措施) setMount(true); }, []); const settings = { lazyload: true, nav: false, mouseDrag: true, loop: true, items: 1, gutter: 20, controls: false, autoplay: true, autoplayHoverPause: true, autoplayButtonOutput: false, speed: 250, autoplayTimeout: 2500, responsive: { 2048: { items: 10, }, 1920: { items: 4, }, 1728: { items: 4, }, 1440: { items: 4, }, 1280: { items: 4, }, 1194: { items: 4, }, 1114: { items: 4, }, 1180: { items: 4, }, 1104: { items: 4, }, 1024: { items: 4, }, 834: { items: 2, }, 820: { items: 2, }, 800: { items: 2, }, 768: { items: 2, }, }, }; if (mount) { return ( <TinySlider settings={settings} onInit={() => {}}> {props.data.map((item) => ( <CarouselItem key={item.id} data={item} /> ))} </TinySlider> ); } return null; } export default Carousel;
额外说明
- 样式导入
"tiny-slider/dist/tiny-slider.css"可以保留静态导入,因为样式文件不会执行JS逻辑,不会触发window错误 - 如果自定义加载组件,可以替换
loading: () => null为你需要的加载UI,比如一个骨架屏
内容的提问来源于stack exchange,提问作者Amir Hossein
相关产品推荐
相关产品推荐

