引用
在某些情况下,你需要直接引用由 Preact 渲染的 DOM 元素或组件。引用允许你执行此操作。
一个典型的用例是测量 DOM 节点的实际大小。虽然可以通过 ref
获取组件实例的引用,但我们通常不建议这样做。它将在父级和子级之间创建硬耦合,从而破坏组件模型的可组合性。在大多数情况下,直接传递回调作为 prop 比直接调用类组件的方法更自然。
createRef
createRef
函数将返回一个仅具有一个属性的普通对象:current
。每当调用 render
方法时,Preact 都会将 DOM 节点或组件分配给 current
。
class Foo extends Component {
ref = createRef();
componentDidMount() {
console.log(this.ref.current);
// Logs: [HTMLDivElement]
}
render() {
return <div ref={this.ref}>foo</div>
}
}
在 REPL 中运行回调引用
获取元素引用的另一种方法是传递函数回调。它需要输入更多内容,但它的工作方式与 createRef
类似。
class Foo extends Component {
ref = null;
setRef = (dom) => this.ref = dom;
componentDidMount() {
console.log(this.ref);
// Logs: [HTMLDivElement]
}
render() {
return <div ref={this.setRef}>foo</div>
}
}
在 REPL 中运行如果 ref 回调被定义为内联函数,它将被调用两次。一次使用
null
,然后使用实际引用。这是一个常见的错误,而createRef
API 通过强制用户检查ref.current
是否已定义,使其更容易一些。
将所有内容放在一起
假设我们有一个场景,我们需要获取 DOM 节点的引用来测量其宽度和高度。我们有一个简单的组件,我们需要用实际测量值替换占位符值。
class Foo extends Component {
// We want to use the real width from the DOM node here
state = {
width: 0,
height: 0,
};
render(_, { width, height }) {
return <div>Width: {width}, Height: {height}</div>;
}
}
只有在调用了 render
方法并且组件已装入 DOM 后,测量才有意义。在此之前,DOM 节点将不存在,尝试测量它也没有多大意义。
class Foo extends Component {
state = {
width: 0,
height: 0,
};
ref = createRef();
componentDidMount() {
// For safety: Check if a ref was supplied
if (this.ref.current) {
const dimensions = this.ref.current.getBoundingClientRect();
this.setState({
width: dimensions.width,
height: dimensions.height,
});
}
}
render(_, { width, height }) {
return (
<div ref={this.ref}>
Width: {width}, Height: {height}
</div>
);
}
}
在 REPL 中运行就是这样!现在,组件在装入时将始终显示宽度和高度。