sourcecode

반응 요소의 너비를 얻는 방법

copyscript 2023. 3. 25. 11:45
반응형

반응 요소의 너비를 얻는 방법

슬라이더 엄지손가락 바로 위에 툴팁을 표시하는 범위 입력을 작성하려고 합니다.

온라인으로 바닐라 JS의 예를 몇 가지 살펴보았는데, 그것을 보완하기 위해서는 요소의 폭이 필요한 것 같습니다.

그래서 난 그냥 원소 폭을 어떻게 구하는지 궁금했어.

JQuery 메서드와 거의 동일합니다.$(element).width()

    class MyComponent extends Component {
      constructor(props){
        super(props)
        this.myInput = React.createRef()
      }

      componentDidMount () {
        console.log(this.myInput.current.offsetWidth)
      }

      render () {
        return (
        // new way - as of React@16.3
        <div ref={this.myInput}>some elem</div>
        // legacy way
        // <div ref={(ref) => this.myInput = ref}>some elem</div>
        )
      }
    }

후크 포함:

const MyComponent = () => {
  const ref = useRef(null);
  useEffect(() => {
    console.log('width', ref.current ? ref.current.offsetWidth : 0);
  }, [ref.current]);
  return <div ref={ref}>Hello</div>;
};

이는 기본적으로 리액트 커스텀 훅에 대한 Marco Antonio의 답변이지만 크기를 조정한 후가 아니라 초기 치수를 설정하도록 수정되었습니다.

export const useContainerDimensions = myRef => {
  const [dimensions, setDimensions] = useState({ width: 0, height: 0 })

  useEffect(() => {
    const getDimensions = () => ({
      width: myRef.current.offsetWidth,
      height: myRef.current.offsetHeight
    })

    const handleResize = () => {
      setDimensions(getDimensions())
    }

    if (myRef.current) {
      setDimensions(getDimensions())
    }

    window.addEventListener("resize", handleResize)

    return () => {
      window.removeEventListener("resize", handleResize)
    }
  }, [myRef])

  return dimensions;
};

같은 방법으로 사용:

const MyComponent = () => {
  const componentRef = useRef()
  const { width, height } = useContainerDimensions(componentRef)

  return (
    <div ref={componentRef}>
      <p>width: {width}px</p>
      <p>height: {height}px</p>
    <div/>
  )
}

실제로 이 크기 조정 논리를 커스텀훅으로 분리하는 것이 좋습니다.다음과 같이 커스텀 훅을 작성할 수 있습니다.

const useResize = (myRef) => {
  const [width, setWidth] = useState(0)
  const [height, setHeight] = useState(0)
  
  const handleResize = useCallback(() => {
      setWidth(myRef.current.offsetWidth)
      setHeight(myRef.current.offsetHeight)
  }, [myRef])

  useEffect(() => {
    window.addEventListener('load', handleResize)
    window.addEventListener('resize', handleResize)

    return () => {
      window.removeEventListener('load', handleResize)
      window.removeEventListener('resize', handleResize)
    }
  }, [myRef, handleResize])

  return { width, height }
}

이렇게 사용할 수 있습니다.

const MyComponent = () => {
  const componentRef = useRef()
  const { width, height } = useResize(componentRef)

  return (
    <div ref={componentRef }>
      <p>width: {width}px</p>
      <p>height: {height}px</p>
    <div/>
  )
}

컴포넌트/요소에 대한 참조를 저장하는 리액트 리액트 useRef 훅을 컴포넌트 렌더링 시에 기동하는 useEffect 훅과 조합하여 사용하는 것이 간단하고 최신 솔루션입니다.

import React, {useState, useEffect, useRef} from 'react';

export default App = () => {
  const [width, setWidth] = useState(0);
  const elementRef = useRef(null);

  useEffect(() => {
    setWidth(elementRef.current.getBoundingClientRect().width);
  }, []); //empty dependency array so it only runs once at render

  return (
    <div ref={elementRef}>
      {width}
    </div>
  )
}

다음은 재렌더 시 불필요한 할당을 회피하는 @mesern 응답의 TypeScript 버전입니다.

import React, { useState, useEffect } from 'react';

export function useContainerDimensions(myRef: React.RefObject<any>) {
  const [dimensions, setDimensions] = useState({ width: 0, height: 0 });

  useEffect(() => {
    const getDimensions = () => ({
      width: (myRef && myRef.current.offsetWidth) || 0,
      height: (myRef && myRef.current.offsetHeight) || 0,
    });

    const handleResize = () => {
      setDimensions(getDimensions());
    };

    if (myRef.current) {
      setDimensions(getDimensions());
    }

    window.addEventListener('resize', handleResize);

    return () => {
      window.removeEventListener('resize', handleResize);
    };
  }, [myRef]);

  return dimensions;
}

필요한 것은 이 질문의 제목인 반응 요소의 폭뿐이라면 이 솔루션을 사용하십시오.

Christopher의 코멘트를 보충합니다.이를 위해 'react-use' 라이브러리를 사용할 수 있습니다.또, 브라우저의 사이즈가 변경되었을 때에도 리슨 합니다.참고: https://github.com/streamich/react-use/blob/master/docs/useMeasure.md

import React from 'react';

import { useMeasure } from 'react-use'; // or just 'react-use-measure'

const sampleView = () => {
 const [ref, { width }] = useMeasure<HTMLDivElement>();
 console.log('Current width of element', width);
 return <div ref={ref}></div>;
};

export default sampleView;

이 문제는 콜백 참조를 사용하여 보다 간단한 방법으로 처리할 수 있습니다.

React를 사용하면 함수를 참조로 전달하여 기본 DOM 요소 또는 구성 요소 노드를 반환합니다.참조: https://reactjs.org/docs/refs-and-the-dom.html#callback-refs

const MyComponent = () => {
    const myRef = node => console.log(node ? node.innerText : 'NULL!');
    return <div ref={myRef}>Hello World</div>;
 }

이 함수는 기본 노드가 변경될 때마다 실행됩니다.업데이트 사이에 null이 되므로 확인해야 합니다.예:

const MyComponent = () => {
    const [time, setTime] = React.useState(123);
    const myRef = node => console.log(node ? node.innerText : 'NULL!');
    setTimeout(() => setTime(time+1), 1000);
    return <div ref={myRef}>Hello World {time}</div>;
}
/*** Console output: 
 Hello World 123
 NULL!
 Hello World 124
 NULL!
...etc
***/

크기 조정은 할 수 없지만(사용자가 윈도우 크기를 조정하려면 청취자 크기를 조정해야 합니다) OP가 요구한 것은 그것이 맞는지 모르겠습니다.또한 이 버전에서는 업데이트로 인한 노드 크기 조정을 처리합니다.

이 아이디어를 바탕으로 한 커스텀 훅을 다음에 나타냅니다.

export const useClientRect = () => {
    const [rect, setRect] = useState({width:0, height:0});
    const ref = useCallback(node => {
        if (node !== null) {
            const { width, height } = node.getBoundingClientRect();
            setRect({ width, height });
        }
    }, []);
    return [rect, ref];
};

위의 내용은 https://reactjs.org/docs/hooks-faq.html#how-can-i-measure-a-dom-node를 기반으로 합니다.

후크는 ref를 건네주는 대신 ref 콜백을 반환합니다.또한 useCallback을 사용하여 매번 새로운 참조 기능을 다시 만들지 않도록 하고 있습니다.필수는 아니지만 모범 사례로 간주됩니다.

사용 방법은 다음과 같습니다(Marco Antonio의 예에 근거).

const MyComponent = ({children}) => {
  const [rect, myRef] = useClientRect();
  const { width, height } = rect;

  return (
    <div ref={myRef}>
      <p>width: {width}px</p>
      <p>height: {height}px</p>
      {children}
    <div/>
  )
}

리액트 훅:

import React, { useState, useEffect,useRef } from 'react';
...
const table1ref = useRef(null);
const [table1Size, table1SizeSet] = useState({
  width: undefined,
  height: undefined,
});

useEffect(() => {
    function handleResize() {
      table1SizeSet({
        width: table1ref.current.offsetWidth,
        height: table1ref.current.offsetHeight,
      });
    }
    window.addEventListener("resize", handleResize);
    handleResize();
    return () => window.removeEventListener("resize", handleResize);        
  }, [ ]);
...
<div  ref={table1ref}>

문의처:

{table1Size.width}

쓰고 싶을 때.

ResizeObserver를 중심으로 구축된 후크를 제공하는 use-resize-observer 라이브러리가 있습니다.

import React from "react";
import useResizeObserver from "use-resize-observer";

const App = () => {
  const { ref, width, height } = useResizeObserver<HTMLDivElement>();

  return (
    <div>
      <div className="instructions">Try resizing this div!</div>
      <div ref={ref} className="box">
        {width}x{height}
      </div>
    </div>
  );
};

렌더링 시 크기 조정 또는 응용 프로그램의 버그가 발생할 수 있는 사용자 창 크기 조정을 방지하기 위해 크기 조정 이벤트를 수신하는 것이 좋습니다.

const MyComponent = ()=> {
  const myRef = useRef(null)

  const [myComponenetWidth, setMyComponentWidth] = useState('')

  const handleResize = ()=>{ 
    setMyComponentWidth(myRef.current.offsetWidth)
  }

  useEffect(() =>{
    if(myRef.current)
      myRef.current.addEventListener('resize', handleResize)

    return ()=> {
     myRef.current.removeEventListener('resize', handleResize)
    }
  }, [myRef])

  return (
  <div ref={MyRef}>Hello</div>
  )
}

페이지 크기를 조정할 때 페이지 렌더링 시 요소의 너비를 얻기 위한 반응의 예를 다음에 나타냅니다.

import { useLayoutEffect, useEffect, useRef, useState } from 'react'
    const MyComponent = ()=> {    
        const ref = useRef(null)
            const [divWidth, setDivWidth] = useState('')
            const handleResize = () => {
                setDivWidth(ref.current.offsetWidth)
            }
            useEffect(() => {
                if (ref.current) window.addEventListener('resize', 
           handleResize)
        
                return () => {
                    window.removeEventListener('resize', handleResize)
                }
            }, [ref])
        
            useLayoutEffect(() => {
                setDivWidth(ref.current.offsetWidth)
            }, [])
        
        return (
             <div ref={ref} className="warper">
                <div style={{ minWidth: divWidth }}>
                    hello
                </div>
             </div>
        )
        }

2023년 리액트 18.x

로 리액트 18의 리액트 18의 리액트 18의 리액트 18의 리액트 을 바꿉니다.useEffect컴포넌트에 대해 초기화 코드를 한 번만 실행하는 것은 유효하지만, "에 도달하기 전에 효과가 필요하지 않을 수 있습니다"를 읽어주세요.useEffect , .을 할 수 있습니다.useSyncExternalStore훅 - 훅 - 훅 -

// useDimensions.js

import { useMemo, useSyncExternalStore } from "react"

function subscribe(callback) {
  window.addEventListener("resize", callback)
  return () => {
    window.removeEventListener("resize", callback)
  }
}

function useDimensions(ref) {
  const dimensions = useSyncExternalStore(
    subscribe,
    () => JSON.stringify({
      width: ref.current?.offsetWidth ?? 0, // 0 is default width
      height: ref.current?.offsetHeight ?? 0, // 0 is default height
    })
  )
  return useMemo(() => JSON.parse(dimensions), [dimensions])
}

export { useDimensions }

이렇게 쓸 수 있어요.

function MyComponent() {
  const ref = useRef(null)
  const {width, height} = useDimensions(ref)
  return <div ref={ref}>
    The dimensions of this div is {width} x {height}
  </div>
}

왜 JSON.stringify?

useSyncExternalStore「 」를 하고 있다.getSnapshot캐시된 값을 반환하는 함수입니다.그렇지 않으면 무한 재검출이 발생합니다.

{width: 300, height: 200} === {width: 300, height: 200}
// => false ❌

JSON.stringify할 수 .

'{"width":300,"height":200}' === '{"width":300,"height":200}'
// => true ✅

★★★★★★★★★★★★★★★★★★★.useMemo후크를 사용하면 후속 렌더링에서 동일한 치수 객체가 반환됩니다.?dimensions 변경,및 사용 시 "" "" "" " " " " " " " " " " " " "useDimensions검증됩됩니니다

즉시 이용 가능한 치수

외의 에서는, 가 「기타」를 가 있습니다.resize이치노하고 있습니다.useEffect단, 이러한 솔루션은 React 18에서 실패합니다.이 솔루션에서는 그렇지 않습니다.useSyncExternalState 번째 에 즉시 할 수 첫 번째 렌더링의 치수에 바로 접근할 수 있습니다!

타이프 스크립트

있습니다useDimensions users - hook hook hook hook hook hook hook hook hook hook hook hook -

import { RefObject, useMemo, useSyncExternalStore } from "react"

function subscribe(callback: (e: Event) => void) {
  window.addEventListener("resize", callback)
  return () => {
    window.removeEventListener("resize", callback)
  }
}

function useDimensions(ref: RefObject<HTMLElement>) {
  const dimensions = useSyncExternalStore(
    subscribe,
    () => JSON.stringify({
      width: ref.current?.offsetWidth ?? 0,
      height: ref.current?.offsetHeight ?? 0,
    })
  )
  return useMemo(() => JSON.parse(dimensions), [dimensions])
}

export { useDimensions }

커스텀 훅

import { useCallback, useState } from "react";

const useContainerDimensions = () => {
  const [size, setRect] = useState(null);
  const ref = useCallback(node => {
    if (node !== null) {
      setRect(node.getBoundingClientRect());
    }
  }, []);
  return [size, ref];
}
export default useContainerDimensions;

이렇게 쓰면 돼요

const [size, ref] = useContainerDimensions();

return (
 <Text ellipsis style={{maxWidth: size?.width}}>
  Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod 
  tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim 
  veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea 
  commodo consequat. Duis aute irure dolor in reprehenderit in voluptate 
  velit esse cillum dolore
 </Text>
)

언급URL : https://stackoverflow.com/questions/43817118/how-to-get-the-width-of-a-react-element

반응형