React:我可以操作DOM React渲染了多少?

时间:2014-05-08 00:27:48

标签: dom reactjs

这就是我正在做的事:http://jsfiddle.net/iamnoah/pTrrw/

关键部分是:

position: function() {
  var container = $(this.getDOMNode());
  this._menu = $(this.refs.menu.getDOMNode());
  this._menu.appendTo(document.body).
      offset({
          top: container.offset().top + 
              container.outerHeight(),
          left: container.offset().left
      });
},
restore: function() {
  this._menu.appendTo(this.getDOMNode());      
},
componentWillUpdate: function() {
  this.restore();
},
componentDidUpdate: function() {
  this.position();
},
componentDidMount: function() {
  this.position();
},

现在效果很好。我假设React在更新之间单独留下DOM并且不会错过它,我会在组件更新之前将内容放回去。事实上,React似乎可以移动内容(如果我移除componentWillUpdatecomponentDidUpdate,定位元素仍会更新!)

我的问题是有多少结果假设是安全的(即,如果我假设这些东西,我的代码是否会在React的未来版本中中断?):

  • 只要您将更新后的内容放回componentWillUpdate,React就不关心DOM是否在更新之间移动。
  • React事件处理程序仍然可以处理已移动的元素。
  • React会将您提出的任何内联样式与元素上已有的样式合并(即使它没有设置它们。)
  • 即使您将DOM移动到文档中的其他位置,React也会更新它已呈现的DOM!

对我来说,最后一个看起来有点极端和神奇,但如果有的话会产生很大的影响。

2 个答案:

答案 0 :(得分:57)

我是React dev。我会回答你的每个问题:


  

只要你将DOM放回componentWillUpdate中,React就不关心DOM是否在更新之间移动。

True - 除了事件处理程序之外,React不会查看DOM,除了事件处理程序:

  

React事件处理程序仍然可以处理已移动的元素。

我不会依赖于此,我不确定它现在是否真实。

  

React会将您要求的任何内联样式与元素上已有的样式合并(即使它没有设置它们。)

我也不会依赖于此 - 现在React设置了各个属性,但我可以很容易地想象它设置el.style.cssText如果它更快,这会吹走你所做的个别更改。

  

即使您将DOM移动到文档中的其他位置,React也会更新它呈现的DOM!

我认为目前这不是真的,你也不应该依赖它。


一般来说,你不应该手动操作React创建的DOM。在React中创建一个空<div>并用手填充它是100%犹太教;只要您以后不尝试在React中更改其属性(导致React执行DOM更新),甚至可以修改React渲染元素的属性,但是如果移动元素,React可能会查找它并且当它找不到它时会感到困惑。

希望有所帮助。

答案 1 :(得分:16)

一方面,我同意Sophie的观点,即您不应该根据实施细节做出决定。但是,我想说React实际上是如何工作的仍然很有趣:

有些事情可能会有所改变,但一般来说这就是发生的事情以及它是如何发生的。

  1. 考虑到React在其创建的每个DOM元素上放置唯一ID(现在是数据属性)这一事实。这些ID目前基于一个非常简单的系统。这应该解释系统 - 根节点总是&#39; .0&#39;

               .0
        .0.0        .0.1
    .0.0.0     .0.1.0 .0.1.1
    
  2. 每当您提供“键”时属性您提供的值用于id而不是列表中的索引,但系统保持不变。

    1. React创建的虚拟DOM也包含具有相同ID的轻量级对象。这是虚拟DOM和真实DOM之间的简单映射系统。

    2. 这也是为什么如果你没有提供关键字,列表中的元素会被覆盖的原因。如果在列表中间添加或删除元素,则元素的id会发生变化。

    3. 牢记这一点:

        

      只要你将DOM放回componentWillUpdate中,React就不关心DOM是否在更新之间移动。

      是。我认为,即使你没有在更新之前把元素放回去,事情也会有效,因为React使用id工作。但这可能是一个非常棘手和不可靠的工作,因为元素可能被添加或删除,事情可能会破裂。

        

      React事件处理程序仍然可以处理已移动的元素。

      是......在某种程度上。事件处理程序的反应方式是所有事件都是合成的。这意味着React根DOM节点上只有一个事件监听器。在那里捕获的所有事件都与React中的事件侦听器匹配。我认为这也使用ID来匹配元素。但是,React可能会对它的父元素进行一些最小的检查。我认为只要元素保存在React呈现的同一根节点内,这就应该有效。也就是说,React可以在将来更新id系统,并在将来对父节点进行更多检查,然后可能会中断。

        

      React会将您要求的任何内联样式与元素上已有的样式合并(即使它没有设置它们。)

      这已经得到了解答。暂时工作,将来可能无法使用。我不会在短期内改变,因为有些动画系统依赖于这个实现细节。

        

      即使您将DOM移动到文档中的其他位置,React也会更新它呈现的DOM!

      是的,如果您使用相同的react-id保留相同的DOM元素,则react将不知道它已在文档中移动,并且只是更新它,就好像它处于呈现它的相同位置一样。正如您已经注意到它需要在同一个React Root中。这很重要,因为React只会绑定到React根DOM节点以获取合成事件等。这样React可以很好地与其他库一起使用,并且不需要访问文档根目录。

      谨慎之言:仅仅因为你可以做某事并不意味着你应该这样做。一般来说,您应该只添加其他DOM节点,并在未由React管理的DOM节点上添加属性(样式:变换值对于动画是常见的)。当你做其他事情时,要明白事情可能会奏效,但通常会有更好的办法。


      至于你的问题:

        

      那你怎么解决我的问题呢?例如,滚动区域内的下拉菜单被溢出切断...我总是将元素移动到正文,但似乎这不是React方式。

      我认为这里的理想情况是将体内下拉开始。然后,您可以在单击事件和下拉列表之间传递消息。 您可以使用回调在虚拟DOM上足够高,然后将道具一直更新到下拉列表以管理它的状态。或者只是使用一个好的ol&#39;事件系统。