首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >反应中的第三方DOM操作

反应中的第三方DOM操作
EN

Stack Overflow用户
提问于 2018-05-08 18:26:06
回答 1查看 2.1K关注 0票数 5

我目前正在将一个遗留的BackboneJS应用程序移植到ReactJS。该应用程序使用VexFlow,JavaScript音乐符号渲染引擎。我遇到的主要问题之一是,VexFlow以类似于D3的方式将所有东西呈现给SVG本身。有很多关于将D3与React结合在一起的信息,在这种情况下,我遵循的似乎是一般的实践,即使用一个空的React ref元素作为我的VexFlow呈现的目标,这一切都发生在componentDidMount中。

代码语言:javascript
复制
export default class ScoreComponent extends React.Component {

  constructor(props) {
    super(props);
    // Create a 'ref' object, which allows us to reference the React DOM
    // element we create in the render method.
    this.scoreElem = React.createRef();
    ...
  }

  componentDidMount() {
    var score = this.score;
    var elem = this.scoreElem.current;
    score.setElem(elem).render(); // <- All VexFlow rendering happens here...
    ...
  }

  render() {
    return (
      <div className="score" id={this.props.scoreId} ref={this.scoreElem}></div>
    );
  }

}

尽管这样做很有效,但这让我感到很不舒服,特别是因为我还必须添加相当数量的jQuery代码来处理SVG元素上的用户交互(例如,单击和拖动复杂的路径对象),而没有一个响应是不会被察觉的。

所以我的问题是:我是否走上了一条会导致我被烧死的道路?我真的很喜欢反应,我渴望和脊梁说再见。我能够在一个周末毫无痛苦地移植我的大部分UI代码。我以前看过棱角,但看起来太复杂了,太固执己见了。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-05-08 21:58:15

你朝正确的方向前进了。当您需要使用外部的非react库来呈现react中的内容时,可以这样做:

  1. 在构造函数中创建DOM元素的引用。
  2. componentDidMount()上启动插件实例,并将对插件实例的引用作为组件实例的属性添加。这将使您能够从其他方法调用实例的方法。
  3. componentDidUpdate()中的支柱变化做出反应。使用插件实例的引用来更新它。
  4. componentWillUnmount()中清除插件添加/计划/等的所有内容.例如事件侦听器、超时/间隔、在反应性树之外创建的DOM节点、正在进行的AJAX调用等.
  5. 在呈现中-不要向容器添加任何属性,这样它就不会在道具/状态更改上被重命名。

注:在反应16.3之前,标准方法是通过在shouldComponentUpdate()中返回false来防止道具/状态的更改,并对componentWillReceiveProps()中的道具变化作出反应。然而,后者正在走向被反对的道路上,而前者将是一种建议,而不是一种严格的命令。

这个(不工作)示例是基于当前的VexFlow教程松散的。

代码语言:javascript
复制
export default class ScoreComponent extends React.Component {
  constructor(props) {
    super(props);
    // 1. create a ref to a DOM element
    this.scoreElem = React.createRef();
    ...
  }

  componentDidMount() {
    const { size } = this.props;
    const elem = this.scoreElem.current;
    // 2. add a reference to the plugin's instance, so you   
    //    can call the plugin in other lifecycle methods
    this.renderer = new VF.Renderer(elem, VF.Renderer.Backends.SVG)
    renderer.resize(size.w, size.h);
    this.context = renderer.getContext();
    ...
  }  

  componentDidUpdate (prevProps) {
    // 3. if the props effect the plugin
    // do something with the plugin
    // for example:
    const { size } = this.props;
    if(size !== prevProps.size) this.renderer.resize(size.w, size.h);
  }

  componentWillUnmount() {
    // 4. teardown:
    // run VexFlow destroy method if available
    // remove non react event listeners
    // clear timeouts and intervals
    // remove DOM nodes rendered outside of react container
    // cancel ongoing AJAX calls
    // etc...
  }

  render() {
    // 5. use only ref on the returned element, any use of properties/state might rerender the element itself.
    return (
      <div className="score" ref={this.scoreElem}></div>
    );
  }

}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50240053

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档