You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React窗口resize时同步两个div高度触发无限循环报错如何解决

问题根源
  • 无限循环的直接原因是你把dimensions作为了修改它本身的useEffect的依赖项:useEffect内调用setDimensions会更新dimensions状态,状态更新又会重新触发useEffect执行,形成死循环。
  • 原有逻辑没有监听窗口resize事件,窗口大小变化时不会自动重新计算两个div的高度,没法做到实时同步。
  • useRef的current属性变化不会触发依赖ref的useEffect重新执行,就算窗口大小变化导致左侧Card高度变了,原逻辑也感知不到。
解决方案

步骤1:封装正确的监听元素尺寸的自定义hook

这个hook会监听窗口resize事件,实时更新目标元素的尺寸,加防抖优化性能,同时避免循环依赖:

const useRefDimensions = (ref) => {
  const [dimensions, setDimensions] = useState({ width: 1, height: 2 })

  useEffect(() => {
    if (!ref.current) return
    // 防抖函数,避免resize频繁触发更新
    let timer = null
    const updateDimensions = () => {
      clearTimeout(timer)
      timer = setTimeout(() => {
        const boundingRect = ref.current.getBoundingClientRect()
        const { width, height } = boundingRect
        setDimensions({ 
          width: Math.round(width), 
          height: Math.round(height) + 35 
        })
      }, 100)
    }
    // 初始化时执行一次
    updateDimensions()
    // 监听窗口resize事件
    window.addEventListener('resize', updateDimensions)
    // 卸载时清理事件和定时器
    return () => {
      clearTimeout(timer)
      window.removeEventListener('resize', updateDimensions)
    }
  }, [ref]) // ref本身引用稳定,不会触发重复执行

  return dimensions
}

步骤2:修改Home组件逻辑

删掉原来组件内部写的有问题的useEffect,直接调用上面封装的自定义hook即可,渲染逻辑和原有代码完全一致:

import React, {useState, useEffect, useRef} from 'react'
import { Card, Row, Col } from 'react-bootstrap'
import PerfectScrollbar from 'react-perfect-scrollbar'
import succession from '../../assets/images/succession/succession.jpeg'
import successiontrailerposter from '../../assets/images/succession/succesion trailer.jpg'
import successiontrailer from '../../assets/images/succession/successionTrailer.mp4'
import {ReactVideo} from 'reactjs-media'

const metadata = [
  {
    title: "Succession",
    source: "HBO",
    type: "Original",
    mediatype: "TV Series",
    rating: "TV-MA",
    seasons: 3,
    episodes: 30,
    poster: succession,
    trailerposter: successiontrailerposter,
    trailer: successiontrailer,
    summary: "When Logan Roy (Brian Cox) announces his plans to step back from running the family's multi-national entertainment company, a feud over who will be have control causes tension among his four children.",
    info: [
      {
        releasedate: "June 3, 2018",
        availabilitydate: "May 27, 2020",
        runtime: "56 - 70 minutes",
        genres:[ "Drama", "Comedy-Drama", "Black-Comedy" ],
        tags: ["Patriarchy", "finance", "based on true story" ],
        regions: ["North America", "Latin America"],
        language: "English",
        awards: ["Golden Globe: Best TV Series"],
        prod_budget: "$50,000,000",
        marketing_budget: "$3,000,000",
      }
    ]

  }
]

// 上面封装的useRefDimensions hook放这里
const useRefDimensions = (ref) => {
  const [dimensions, setDimensions] = useState({ width: 1, height: 2 })

  useEffect(() => {
    if (!ref.current) return
    let timer = null
    const updateDimensions = () => {
      clearTimeout(timer)
      timer = setTimeout(() => {
        const boundingRect = ref.current.getBoundingClientRect()
        const { width, height } = boundingRect
        setDimensions({ 
          width: Math.round(width), 
          height: Math.round(height) + 35 
        })
      }, 100)
    }
    updateDimensions()
    window.addEventListener('resize', updateDimensions)
    return () => {
      clearTimeout(timer)
      window.removeEventListener('resize', updateDimensions)
    }
  }, [ref])

  return dimensions
}

const Home = () => {
    const divRef = useRef()
    // 直接调用自定义hook获取尺寸
    const dimensions = useRefDimensions(divRef)

  return (
    <div className="container-fluid pt-3 px-5">
      {metadata.map((item, index) => {
        return (
          <div key={index}>
            <div className="d-flex align-items-end justify-content-between pb-4">
              <h1 className="item-title m-0 text-primary text-bold">{item.title}</h1>
              <div className="d-flex flex-column align-items-end justify-content-end">
                <p className="m-0">{item.source} {item.type} | {item.mediatype} | {item.rating}</p>
                <p className="m-0">Seasons: {item.seasons} ({item.episodes} episodes)</p>
              </div>
            </div>
            <Row>
              <Col xs={12} md={3} lg={2}>
                <Card bg="dark">
                  <Card.Img variant="top" src={item.poster} />
                </Card>
              </Col>
              <Col xs={12} md={9} lg={10}>
                <Row className="media-info">
                  <Col 
                    md={12} 
                    lg={7} 
                    className="media-container" >
                    <Card bg="dark" ref={divRef}>
                      <ReactVideo 
                        src={item.trailer} 
                        poster={item.trailerposter} 
                        className="video-player"/>      
                    </Card>
                  </Col>
                  <Col 
                    md={12} 
                    lg={5} 
                    className="metadata-container" >
                    <PerfectScrollbar style={{ height: dimensions.height }}>
                      <Card bg="dark">
                        <Card.Body>
                          <div className="mb-3">
                            <h4 className="card-h4">Series Summary</h4>
                            <p className="card-p">{item.summary}</p>
                          </div>
                          <div>
                            <h4 className="card-h4">Series Metadata</h4>
                            <ul className="card-ul">
                              <li>
                                <label>Release Date: </label>
                                <span>{item.info[0].releasedate}</span>
                              </li>
                              <li>
                                <label>HBO Max First Availability Date: </label>
                                <span>{item.info[0].availabilitydate}</span> 
                              </li>
                              <li>
                                <label>Runtime: </label>
                                <span>{item.info[0].runtime}</span> 
                              </li>
                              <li>
                                <label>Genre(s): </label>
                                { item.info[0].genres.map((genre, index) => {
                                  return (
                                    <span key={`genre_${index}`}>
                                      { (index ? ', ' : '') + genre }
                                    </span>                          
                                  )
                                })} 
                              </li>
                              <li>
                                <label>Plot Tag(s): </label>                          
                                { item.info[0].tags.map((tag, index) => {
                                  return (
                                    <span key={`tag_${index}`}>
                                      { (index ? ', ' : '') + tag }
                                    </span>                          
                                  )
                                })} 
                              </li>
                              <li>
                                <label>Region Availability: </label>
                                { item.info[0].regions.map((region, index) => {
                                  return (
                                    <span key={`region_${index}`}>
                                      { (index ? ', ' : '') + region }
                                    </span>                          
                                  )
                                })}
                              </li>
                              <li>
                                <label>Original Language: </label>
                                <span>{item.info[0].language}</span>
                              </li>
                              <li>
                                <label>Awards: </label>
                                { item.info[0].awards.map((award, index) => {
                                  return (
                                    <span key={`award_${index}`}>
                                      { (index ? ', ' : '') + award }
                                    </span>                          
                                  )
                                })}
                              </li>
                              <li>
                                <label>Production Budget: </label>
                                <span>{item.info[0].prod_budget}</span> 
                              </li>
                              <li>
                                <label>Marketing Budget: </label>
                                <span>{item.info[0].marketing_budget} </span>
                              </li>
                            </ul>
                          </div>
                        </Card.Body>
                      </Card>
                    </PerfectScrollbar>
                  </Col>
                </Row>
              </Col>
              
            </Row>
          </div>
        )
      })}
    </div>
  )
}

export default Home

内容的提问来源于stack exchange,提问作者LOTUSMS

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 09:36:06