React图片轮播setTimeout执行时报Cannot read properties of undefined (reading 'style')错误
报错原因
出现TypeError: Cannot read properties of undefined (reading 'style')是因为代码访问ImgContainer.current.style的时候,ImgContainer.current为undefined,触发的场景有以下几个:
- 你没有把
setTimeout放到副作用钩子中,组件每次重渲染都会生成新的5秒定时器,旧定时器没有被清理,当定时器触发时可能组件已经卸载、或者DOM还未完成挂载,ref还没有绑定到对应的div元素上 - 你没有对ref.current做非空校验,只要ref绑定失败就会直接抛出异常
- 另外你的代码还存在其他逻辑问题:handleNext中重复调用setposition会导致position计数错误,没有做轮播边界判断会出现滑到空白区域的问题,也没有实现用户操作后重置5秒倒计时的需求逻辑
修复方案
调整后的完整代码如下,所有问题都已修复:
import React, { useRef, useState, useEffect } from 'react' import BeforeIcon from "../assests/before.svg" import NextIcon from "../assests/next.svg" import Banner1 from "../assests/banner1.jpg" import Banner2 from "../assests/banner2.jpg" import "../styles/banner.css" export default function Banner() { const ImgContainer = useRef(null) const timerRef = useRef(null) // 对应轮播图的总数量,可根据实际情况调整 const TOTAL_SLIDES = 7 const [position, setPosition] = useState(0) const [w, setW] = useState(window.innerWidth) // 重置自动轮播倒计时 const resetAutoTimer = () => { if (timerRef.current) clearTimeout(timerRef.current) timerRef.current = setTimeout(() => { handleNext() }, 5000) } const handleNext = () => { // 边界判断:滑到最后一张后回到第一张 const newPosition = position === TOTAL_SLIDES - 1 ? 0 : position + 1 const move = w * newPosition setPosition(newPosition) // 非空校验后再操作DOM,避免报错 if (ImgContainer.current) { ImgContainer.current.style.transform = `translateX(-${move}px)` ImgContainer.current.style.transition = "transform 1s" } // 用户主动操作后重置自动轮播 resetAutoTimer() } const handleBefore = () => { // 边界判断:滑到第一张后回到最后一张 const newPosition = position === 0 ? TOTAL_SLIDES - 1 : position - 1 const move = w * newPosition setPosition(newPosition) if (ImgContainer.current) { ImgContainer.current.style.transform = `translateX(-${move}px)` ImgContainer.current.style.transition = "transform 1s" } resetAutoTimer() } useEffect(() => { // 初始化自动轮播 resetAutoTimer() // 监听窗口宽度变化,适配窗口缩放场景 const handleResize = () => setW(window.innerWidth) window.addEventListener('resize', handleResize) // 组件卸载时清理定时器和监听事件,避免内存泄漏和无效执行 return () => { if (timerRef.current) clearTimeout(timerRef.current) window.removeEventListener('resize', handleResize) } }, [position]) return ( <section> <button onClick={handleBefore}><img src={BeforeIcon} alt="" className="button right"/></button> <div ref={ImgContainer} className="imgcontainer"> <img src={Banner2} alt="" className="bannerimg"/> <img src={Banner2} alt="" className="bannerimg"/> <img src={Banner2} alt="" className="bannerimg"/> <img src={Banner2} alt="" className="bannerimg"/> <img src={Banner1} alt="" className="bannerimg"/> <img src={Banner1} alt="" className="bannerimg"/> <img src={Banner1} alt="" className="bannerimg"/> </div> <button onClick={handleNext}><img src={NextIcon} alt="" className="button left"/></button> </section> ) }
内容的提问来源于stack exchange,提问作者Mike
相关产品推荐
相关产品推荐

