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

IT技术 dom reactjs
2021-04-20 23:12:55

这就是我正在做的:jsfiddle

临界区是:

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 似乎可以处理移动内容(如果我删除componentWillUpdateand componentDidUpdate,定位元素仍然更新!)

我的问题是有多少由此产生的假设是安全的(即,如果我假设这些事情,我的代码会在 React 的未来版本中崩溃吗?):

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

最后一个对我来说似乎有些极端和神奇,但如果它成立,则具有一些重大意义。

2个回答

我是一个 React 开发者。我会回答你的每一个问题:


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

是的——React 不查看 DOM,除了更新时,事件处理程序除外:

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

我不会依赖这个,而且我现在不确定它是否正确。

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

我也不会依赖这个——现在 React 设置单个属性,但我可以很容易地想象它设置el.style.cssText得更快,这会破坏你所做的单个更改。

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

我不相信目前这是真的,你也不应该依赖这一点。


从广义上讲,您不应该手动操作 React 创建的 DOM。<div>在 React 中创建一个空的并手动填充它是 100% kosher 的甚至可以修改 React 渲染元素的属性,只要您稍后不尝试在 React 中更改其属性(导致 React 执行 DOM 更新),但是如果您移动一个元素,React 可能会寻找它并当它找不到它时会感到困惑。

希望有帮助。

@Ben Alpert,我可以请您在此处查看与反应相关的问题: stackoverflow.com/questions/27913004/...
2021-05-23 23:12:55
谢谢!很有启发性。
2021-05-25 23:12:55
“即使您将该 DOM 移动到文档中的其他位置,React 也会更新它已呈现的 DOM!” 如果 DOM 保持在 React 根中,则似乎是正确的。我猜实施的运气。
2021-06-13 23:12:55
太棒了,这很棒,我最终选择了 componentWillUpdate/componentDidUpdate(移动节点)。但是,如果我需要大量更新状态,我将不得不中断并仅依靠 componentDidMount/componentWillUnmount 进行清理。
2021-06-15 23:12:55
那你怎么解决我的问题?例如,滚动区域内的下拉菜单被溢出截断......我总是将元素移动到正文,但这似乎不是 React 的方式。
2021-06-20 23:12:55

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

有些事情可能已经发生了一些变化,但通常这就是发生的事情以及它是如何发生的。

  1. 考虑这样一个事实,即 React 在它创建的每个 DOM 元素上都放置了唯一的 id(现在是数据属性)。这些 ID 目前基于一个非常简单的系统。这应该解释系统 - 根节点总是“.0”

               .0
        .0.0        .0.1
    .0.0.0     .0.1.0 .0.1.1
    

每当您提供“键”属性时,您提供的值将用于 id 而不是列表中的索引,但系统保持不变。

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

  2. 这也是为什么如果您不提供“key”属性,则列表中的元素会被覆盖的原因,因为如果在列表中间添加或删除元素,元素的 id 会发生变化。

牢记这一点:

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

是的。我认为即使您在更新之前不将元素放回原处,事情也可能会起作用,因为 React 使用 ids 工作。但这将是一个非常棘手且不可靠的工作,因为可能会添加或删除元素并且事情可能会破裂。

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

是的……在某种程度上。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 上达到足够高的位置,然后一直更新到下拉菜单中的 props 以管理它的状态。或者只是使用一个好的 ol' 事件系统。