如何使用React useRef Hook获取组件高度?按钮高度判断逻辑异常问题排查
Hey there! Let's break down your two questions about using React's useRef hook and the issue with your button loading component.
问题1:如何使用React的useRef Hook获取组件的高度?
To get a component's height with useRef, you need to follow a couple key steps—since refs don't populate until the component mounts, you can't just grab the height on initial render. Here's a straightforward approach:
- Create a ref with
useRefand attach it to your target element. - Use
useEffectto access the ref after the component has mounted (this ensures the DOM element exists). - Choose the right height property based on your needs:
clientHeight: Includes the element's content + padding, excludes borders, margins, and scrollbars.offsetHeight: Includes content + padding + borders, and accounts for scrollbars if present.scrollHeight: Measures the full height of the element's content (even parts hidden by overflow), excluding borders/margins.
Example Code:
import { useRef, useEffect } from 'react'; function MyComponent() { const elementRef = useRef(null); useEffect(() => { if (elementRef.current) { const componentHeight = elementRef.current.clientHeight; console.log('Component height:', componentHeight); } }, []); // Empty dependency array runs this only after initial mount return ( <div ref={elementRef} style={{ height: '120px', padding: '1rem', border: '1px solid #ccc' }}> This is my component </div> ); }
问题2:为什么按钮高度为50px时仍显示SpinnerTwo组件?
Looking at your code, there are two main issues causing this unexpected behavior:
- Ref is null on initial render: When the component first renders,
refButton.currenthasn't been attached to the button element yet. SorefButton.current?.clientHeightreturnsundefined, which doesn't equal 50—henceSpinnerTworenders first. - Ref changes don't trigger re-renders: Even after the ref attaches to the button, updating the ref doesn't cause the component to re-render. So your condition never gets re-evaluated with the actual height value.
Fix: Combine useRef with useState and useEffect
We'll use useState to store the button height (so changes trigger re-renders) and useEffect to fetch the height after mount (and listen for resizes if needed):
import { useRef, useEffect, useState } from 'react'; import styled from 'styled-components'; const Button = styled.button` height: 50px; `; function ButtonLoading({ onClick }) { const refButton = useRef<HTMLButtonElement | null>(null); const [buttonHeight, setButtonHeight] = useState(0); useEffect(() => { const updateHeight = () => { if (refButton.current) { setButtonHeight(refButton.current.clientHeight); } }; // Run once after mount to get initial height updateHeight(); // Optional: Listen for window resizes if your button might change height responsively window.addEventListener('resize', updateHeight); // Clean up the event listener when component unmounts return () => window.removeEventListener('resize', updateHeight); }, []); return ( <Button ref={refButton} onClick={onClick}> {buttonHeight === 50 ? <SpinnerOne /> : <SpinnerTwo />} </Button> ); }
Quick Note:
If you need the height immediately after DOM updates (before the browser paints), you can swap useEffect with useLayoutEffect—it runs synchronously after DOM mutations, which can be useful for layout-related calculations.
内容的提问来源于stack exchange,提问作者Rafael

