gpt4 book ai didi

javascript - 当元素在 DOM 中的位置改变时,是否有可能让 React 移动元素而不是重新创建它?

转载 作者:数据小太阳 更新时间:2023-10-29 06:14:58 30 4
gpt4 key购买 nike

当元素在 DOM 中的位置发生变化时,是否有可能让 React 移动元素而不是重新创建它?

假设我正在制作一个包含 2 个 Pane 的组件,并且我希望能够隐藏/取消隐藏一个 Pane 。让我们也想象一下 Pane 本身很重。在我的例子中,每个 Pane 都有 2000 多个元素。

在我的实际代码中,当有 2 个 Pane 时,我使用了拆分器。为了只显示一个 Pane ,我需要移除拆分器并将其替换为一个 div。

下面的代码对此进行了模拟。如果只有一个 Pane ,它会使用 div 来包含该 Pane 。如果有 2 个 Pane ,它会使用 pre 来包含它们。在我的例子中,它是 div 有 1 个痛点和一个 splitter 有 2 个痛点。

因此,检测 document.createElement 我看到不仅创建了容器,而且重新创建了其中的元素。换句话说,在我的代码中,当从 splitter->div 开始时,2000 多个元素 Pane 将完全重新创建,这很慢。

有没有办法有效地告诉 React。 “嘿嘿,这个组件不要重新创建,直接移动它好吗?”

class TwoPanes extends React.Component {
constructor(props) {
super(props);
}
render() {
const panes = this.renderPanes();
if (panes.length === 2) {
return React.createElement('pre', {className: "panes"}, panes);
} else {
return React.createElement('div', {className: "panes"}, panes);
}
}
renderPanes() {
return this.props.panes.map(pane => {
return React.createElement('div', {className: "pane"}, pane);
});
}
}

class App extends React.Component {
constructor(props) {
super(props);
this.state = {
panes: [
"pane one",
"pane two",
],
};
}
render() {
const panes = React.createElement(TwoPanes, {panes: this.state.panes}, null);
const button = React.createElement('button', {
onClick: () => {
const panes = this.state.panes.slice();
if (panes.length === 1) {
panes.splice(0, 0, "pane one"); // insert pane 1
} else {
panes.splice(0, 1); // remove pane 1
}
this.setState({panes: panes});
},
}, "toggle pane one");
return React.createElement('div', {className: "outer"}, [panes, button]);
}
}

// wrap document.createElement so we can see if new elements are created
// vs reused
document.createElement = (function(oldFn) {
let count = 0;
let inside = false;
return function(type, ...args) {
if (!inside) { // needed because SO's console wrapper calls createElement
inside = true;
console.log(++count, "created:", type);
inside = false;
}
return oldFn.call(this, type, ...args);
}
}(document.createElement));


ReactDOM.render(
React.createElement(App, {}, null),
document.getElementById('root')
);
html { box-sizing: border-box; }
*, *:before, *:after { box-sizing: inherit; }
body { margin: 0; }
#root { width: 100vw; height: 100vh; }
.outer {
width: 100%;
height: 100%;
}
.panes {
width: 100%;
height: 100%;
display: flex;
flow-direction: row;
justify-content: space-between;
}
.pane {
flex: 1 1 auto;
border: 1px solid black;
}
button {
position: absolute;
left: 10px;
top: 30px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

最佳答案

我不认为有一种方法可以在 DOM 树中移动,即使有 - 它会非常昂贵,因为

  • React's diff algorithm仍然需要比较不同的树,如果它偶然发现具有不同结构的子树/节点,它将立即丢弃旧的。这是 diff 算法为了在 O(n)
  • 中运行而做出的假设之一

Two elements of different types will produce different trees

  • 为了在缓存的 DOM 中移动,您首先需要将它从树中分离出来,这意味着它仍然需要稍后重新应用,这是一个瓶颈。将 HTML 插入到 DOM 中非常昂贵,即使已缓存/预呈现也是如此。

我的建议是使用 CSS,因为 display: none/display: block 比重新应用缓存的 DOM 快得多

class TwoPanes extends React.Component {

render() {
return (
<div>
<Pane1 />
<Pane2 style={this.state.panes.length === 2 ? {} : {display: 'none'} } />
</div>
);
}
}

关于javascript - 当元素在 DOM 中的位置改变时,是否有可能让 React 移动元素而不是重新创建它?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41124310/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com