这可以通过使用 callback refs 以更简单的方式处理。
React 允许你将一个函数传递给一个 ref,它返回底层的 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>;
}
只要底层节点发生变化,这个函数就会被触发。在更新之间它将为空,因此我们需要检查这一点。示例:
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
注意钩子返回一个引用回调,而不是传递一个引用。我们使用 useCallback 来避免每次都重新创建一个新的 ref 函数;不重要,但被认为是良好的做法。
用法是这样的(基于 Marco Antônio 的示例):
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/>
)
}