React TypeError:无法读取未定义的属性“getBoundingClientRect”

Posted

技术标签:

【中文标题】React TypeError:无法读取未定义的属性“getBoundingClientRect”【英文标题】:React TypeError: Cannot read property 'getBoundingClientRect' of undefined 【发布时间】:2021-04-17 02:02:42 【问题描述】:

服务器:Node.js、MongoDB、Graphql前端:React --typescript、apollo-client、Graphql

我认为带来数据并渲染它是时间或顺序的问题。尽管如此,我还是找不到解决这个问题的办法。

错误


    未捕获的类型错误:无法读取未定义的属性“getBoundingClientRect”。 未捕获(承诺中)类型错误:无法读取未定义的属性“getBoundingClientRect”。

代码


import React,  MutableRefObject, useCallback, useLayoutEffect, useRef, useState  from 'react';
import  gql, useQuery  from '@apollo/client';
import  MainSlide  from '../../components';
import  MSlidersItf, MSlideItf  from '../../types';
import * as S from './MainSliderStyle';
import  GetWindowWidth  from '../../api/window-width/WindowWidth';

const GET_MAINSLIDERS = gql`
  query 
    getMainSliders 
      idx
      title 
        en
        ko
      
      text 
        en
        ko
      
      url
      src
      postingDate
    
  
`;

const SlideMapForm = (item: MSlideItf, i: number, Count: number) => 
  return (
    <MainSlide
      key=String(i + Count)
      title=item.title
      text=item.text
      url=item.url
      src=item.src
      postingDate=item.postingDate
    />
  );
;
export default function TestBtn() 
  const  loading, error, data  = useQuery<MSlidersItf>(GET_MAINSLIDERS);
  const MSlidersLength = data && data?.getMainSliders.length;
  const TotalSlideCount = MSlidersLength! + 4;

  // Ref
  const slidersRef = useRef() as MutableRefObject<htmlDivElement>;

  // getSize
  const windowWidth: number = GetWindowWidth(); // Browser window width
  const [elWidth, setElWidth] = useState(0);
ERROR----------------------------------------------------------------------------------------
  const getEleWidth = useCallback(() => 
    if (data) 
      const  width  = slidersRef.current.children[2].getBoundingClientRect();
      setElWidth(width + 16); // Add Slide Margin
    
  , [data]);
ERROR----------------------------------------------------------------------------------------
  const sliderMargin: number = (windowWidth - elWidth) / 2;

  // Slide to Center
  const [center, setCenter] = useState(2);
  const sliderPosition: number = elWidth * center - sliderMargin; // Slide Position Inital Value

  // sliderControll
  const prevButton = () => setCenter(center - 1);
  const nextButton = () => setCenter(center + 1);

  useLayoutEffect(() => 
ERROR----------------------------------------------------------------------------------------
    getEleWidth();
ERROR----------------------------------------------------------------------------------------
    const resizeLitener = () => 
      const timing = setTimeout(() => getEleWidth(), 150);
      clearTimeout(timing);
    ;

    window.addEventListener('resize', resizeLitener);
    window.addEventListener('load', resizeLitener);

    return () => 
      window.removeEventListener('resize', resizeLitener);
      window.removeEventListener('load', resizeLitener);
    ;
  , [TotalSlideCount, center, data, elWidth, getEleWidth, sliderPosition]);

  if (loading) return <h1>Loding...</h1>;
  if (error) return console.log(`MainSliders DB Error $error`);
  return (
    <S.Wrap>
      data && (
        <S.SlidersArea ref=slidersRef position=sliderPosition>
          Object.values(data.getMainSliders)
            .slice(-2)
            .map((item, i) => SlideMapForm(item, i, -MSlidersLength!))
          Object.values(data.getMainSliders).map((item, i) => SlideMapForm(item, i, 0))
          Object.values(data.getMainSliders)
            .slice(-2)
            .map((item, i) => SlideMapForm(item, i, MSlidersLength!))
        </S.SlidersArea>
      )
      <S.Arrows onClick=prevButton>
        <S.Prev>
          <img src="/img/icon/arrow-next.svg"  />
        </S.Prev>
        <S.Next onClick=nextButton>
          <img src="/img/icon/arrow-next.svg"  />
        </S.Next>
      </S.Arrows>
    </S.Wrap>
  );


【问题讨论】:

【参考方案1】:

试试这个:

const getEleWidth = useCallback(() => 
  if (data) 
    const defaultValue =  width: 0 ;
    const  width  = slidersRef.current?.children?[2]?.getBoundingClientRect?.() || defaultValue; // just check if the element you want exist 
    setElWidth(width + 16);
  
, [data, slidersRef.current]); //<=== add slidersRef to your dependencies

【讨论】:

【参考方案2】:

除了检查对象是否存在(如 Taghi Khavari 提到的),您可以尝试给它一个超时,以便您可以正确渲染您的 dom 元素。 它从来都不是最好的解决方案,但它可以让你的脚本快速运行。

(打算使用Taghi的解决方案)

const defaultValue =  width: 0 ;
setTimeout( () => 
const  width  = slidersRef.current?.children?[2]?.getBoundingClientRect?.() || defaultValue; // just check if the element you want exist 
setElWidth(width + 16);, 20) // You can change the number of milliseconds depending on your rendering

【讨论】:

以上是关于React TypeError:无法读取未定义的属性“getBoundingClientRect”的主要内容,如果未能解决你的问题,请参考以下文章

React - TypeError:无法读取未定义的属性“img”

TypeError:无法读取未定义的属性“长度”(React,heroku)

未处理的拒绝(TypeError):在 React 中使用 useRef 时无法读取未定义的属性(读取“值”)

React Native - TypeError:无法读取未定义的属性“干净”

TypeError:无法读取 React 未定义的属性“标题”

REACT JS:TypeError:无法读取未定义的属性“参数”