帮助
支持我们

外部 DOM 突变

有时需要使用第三方库,这些库期望能够自由地改变 DOM,在其中保留状态,或者根本没有组件边界。有许多出色的 UI 工具包或可重用元素以这种方式运行。

在 Preact(以及类似的 React)中,使用这些类型的库需要您告诉虚拟 DOM 渲染/差异算法,它不应该尝试撤消在给定组件(或它表示的 DOM 元素)内执行的任何外部 DOM 突变。



技术

这可以像在组件上定义一个 shouldComponentUpdate() 方法并让它返回 false 一样简单

class Block extends Component {
  shouldComponentUpdate() {
    return false;
  }
}

... 或使用简写

class Block extends Component {
  shouldComponentUpdate = () => false;
}

通过使用此生命周期钩子并告诉 Preact 在 VDOM 树发生更改时不要重新渲染组件,您的组件现在可以引用其根 DOM 元素,该元素可以被视为静态元素,直到组件卸载。与任何组件一样,该引用被称为 this.base,并且对应于从 render() 返回的根 JSX 元素。


示例演练

下面是一个“关闭”组件重新渲染的示例。请注意,render() 仍作为创建和挂载组件的一部分被调用,以便生成其初始 DOM 结构。

class Example extends Component {
  shouldComponentUpdate() {
    // do not re-render via diff:
    return false;
  }

  componentWillReceiveProps(nextProps) {
    // you can do something with incoming props here if you need
  }

  componentDidMount() {
    // now mounted, can freely modify the DOM:
    let thing = document.createElement('maybe-a-custom-element');
    this.base.appendChild(thing);
  }

  componentWillUnmount() {
    // component is about to be removed from the DOM, perform any cleanup.
  }

  render() {
    return <div class="example" />;
  }
}

演示

demo

在 Webpackbin 上查看此演示

真实世界示例

或者,在 preact-token-input 中查看此技术的实际应用 - 它使用组件作为 DOM 中的立足点,但随后禁用更新并让 tags-input 从那里接管。一个更复杂的示例是 preact-richtextarea,它使用此技术来避免重新渲染可编辑的 <iframe>