引用

¥References

总会有一些场景需要直接引用 Preact 渲染的 DOM 元素或组件。参考文献可以让你做到这一点。

¥There will always be scenarios where you need a direct reference to the DOM-Element or Component that was rendered by Preact. Refs allow you to do just that.

它的一个典型用例是测量 DOM 节点的实际大小。虽然可以通过 ref 获取对组件实例的引用,但我们通常不推荐这样做。它将在父级和子级之间创建硬耦合,从而破坏组件模型的可组合性。在大多数情况下,更自然的做法是将回调作为 prop 传递,而不是尝试直接调用类组件的方法。

¥A typical use case for it is measuring the actual size of a DOM node. While it's possible to get the reference to the component instance via ref we don't generally recommend it. It will create a hard coupling between a parent and a child which breaks the composability of the component model. In most cases it's more natural to just pass the callback as a prop instead of trying to call the method of a class component directly.



createRef

createRef 函数将返回一个只有一个属性的普通对象:current。每当调用 render 方法时,Preact 都会将 DOM 节点或组件分配给 current

¥The createRef function will return a plain object with just one property: current. Whenever the render method is called, Preact will assign the DOM node or component to current.

class Foo extends Component {
  ref = createRef();

  componentDidMount() {
    console.log(this.ref.current);
    // Logs: [HTMLDivElement]
  }

  render() {
    return <div ref={this.ref}>foo</div>
  }
}
Run in REPL

回调参考

¥Callback Refs

获取元素引用的另一种方法可以通过传递函数回调来完成。它的输入量要多一些,但其工作方式与 createRef 类似。

¥Another way to get the reference to an element can be done by passing a function callback. It's a little more to type, but it works in a similar fashion as 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>
  }
}
Run in REPL

如果 ref 回调被定义为内联函数,它将被调用两次。一次使用 null,然后使用实际参考。这是一个常见错误,createRef API 通过强制用户检查 ref.current 是否已定义而使此问题变得更容易。

¥If the ref callback is defined as an inline function it will be called twice. Once with null and then with the actual reference. This is a common error and the createRef API makes this a little easier by forcing user to check if ref.current is defined.

把它们放在一起

¥Putting it all together

假设我们有一个场景,需要获取 DOM 节点的引用来测量其宽度和高度。我们有一个简单的组件,需要用实际测量的值替换占位符值。

¥Let's say we have a scenario where we need to get the reference to a DOM node to measure its width and height. We have a simple component where we need to replace the placeholder values with the actual measured ones.

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 节点将不存在,并且尝试测量它也没有多大意义。

¥Measurement only makes sense once the render method has been called and the component is mounted into the DOM. Before that the DOM node won't exist and there wouldn't make much sense to try to measure it.

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>
    );
  }
}
Run in REPL

就是这样!现在,组件在安装时将始终显示宽度和高度。

¥That's it! Now the component will always display the width and height when it's mounted.

Preact 中文网 - 粤ICP备13048890号