gpt4 book ai didi

javascript - react 性能: rendering big list with PureRenderMixin

转载 作者:行者123 更新时间:2023-12-03 13:03:32 51 4
gpt4 key购买 nike

我用一个 TodoList 示例来反射(reflect)我的问题,但显然我的实际代码更复杂。

我有一些像这样的伪代码。

var Todo = React.createClass({
mixins: [PureRenderMixin],
............
}

var TodosContainer = React.createClass({
mixins: [PureRenderMixin],

renderTodo: function(todo) {
return <Todo key={todo.id} todoData={todo} x={this.props.x} y={this.props.y} .../>;
},

render: function() {
var todos = this.props.todos.map(this.renderTodo)
return (
<ReactCSSTransitionGroup transitionName="transition-todo">
{todos}
</ReactCSSTransitionGroup>,
);
}

});

我的所有数据都是不可变的,PureRenderMixin 使用得当,一切正常。当修改 Todo 数据时,仅重新渲染父级和编辑后的 ​​todo。

问题是,在某些时候,随着用户滚动,我的列表会变大。当更新单个待办事项时,渲染父级需要越来越多的时间,对所有待办事项调用 shouldComponentUpdate,然后渲染单个待办事项。

正如您所看到的,Todo 组件除了 Todo 数据之外还有其他组件。这是所有待办事项渲染所需的数据,并且是共享的(例如,我们可以想象待办事项有一个“displayMode”)。拥有许多属性会使 shouldComponentUpdate 执行速度稍微慢一些。

此外,使用 ReactCSSTransitionGroup 似乎也会减慢一点,因为 ReactCSSTransitionGroup 必须在 之前渲染自身和 ReactCSSTransitionGroupChild调用todos的shouldComponentUpdateReact.addons.Perf 显示 ReactCSSTransitionGroup > ReactCSSTransitionGroupChild 渲染列表中的每个项目都浪费了时间。

因此,据我所知,我使用 PureRenderMixin 但对于较大的列表,这可能还不够。我的性能仍然还不错,但想知道是否有简单的方法来优化我的渲染。

有什么想法吗?

<小时/>

编辑:

到目前为止,我的大列表已分页,因此我现在不再有一个大的项目列表,而是将这个大列表拆分为页面列表。这允许获得更好的性能,因为每个页面现在都可以实现shouldComponentUpdate。现在,当页面中的某个项目发生变化时,React 只需调用在页面上迭代的主渲染函数,并且只从单个页面调用渲染函数,这大大减少了迭代工作。

但是,我的渲染性能仍然与我拥有的页数 (O(n)) 呈线性关系。因此,如果我有数千页,它仍然是同样的问题:)在我的用例中,它不太可能发生,但我仍然对更好的解决方案感兴趣。

我非常确定可以通过将大型列表拆分为树(如持久数据结构)来实现 O(log(n)) 渲染性能,其中 n 是项目(或页面)的数量,并且其中每个节点都有权使用 shouldComponentUpdate 来短路计算

是的,我正在考虑类似于 Scala 或 Clojure 中的 Vector 等持久数据结构的东西:

http://hypirion.com/imgs/pvec/9-annotated.png

但是我担心 React,因为据我所知,它在渲染树的内部节点时可能必须创建中间 dom 节点。根据用例,这可能是一个问题( and may be solved in future versions of React )

此外,由于我们使用的是 Javascript,我想知道 Immutable-JS 是否支持这一点,并使“内部节点”可访问。请参阅:https://github.com/facebook/immutable-js/issues/541

编辑:我的实验的有用链接:Can a React-Redux app really scale as well as, say Backbone? Even with reselect. On mobile

最佳答案

在我们的产品中,我们还遇到了与渲染的代码量相关的问题,我们开始使用可观察量(请参阅此 blog )。这可能会部分解决您的问题,因为更改待办事项将不再需要重新渲染保存列表的父组件(但添加仍然需要)。

它还可以帮助您更快地重新渲染列表,因为当 shouldComponentUpdate 上的 props 更改时,您的 todoItem 组件可能会返回 false。

为了在渲染概述时进一步提高性能,我认为您的树/分页想法确实很好。使用 observable 数组,每个页面都可以开始监听一定范围内的数组拼接(使用 ES7 polyfill 或 mobservable)。这会引入一些管理,因为这些范围可能会随着时间的推移而改变,但应该会让你达到 O(log(n))

所以你会得到类似的东西:

var TodosContainer = React.createClass({
componentDidMount() {
this.props.todos.observe(function(change) {
if (change.type === 'splice' && change.index >= this.props.startRange && change.index < this.props.endRange)
this.forceUpdate();
});
},

renderTodo: function(todo) {
return <Todo key={todo.id} todoData={todo} x={this.props.x} y={this.props.y} .../>;
},

render: function() {
var todos = this.props.todos.slice(this.props.startRange, this.props.endRange).map(this.renderTodo)
return (
<ReactCSSTransitionGroup transitionName="transition-todo">
{todos}
</ReactCSSTransitionGroup>,
);
}

});

大型列表和 React 的核心问题似乎是你不能将新的 DOM 节点转移到 dom 中。否则,您根本不需要“页面”来将数据划分为更小的 block ,您只需将一个新的 Todo 项拼接到 dom 中,就像在 jsFiddle 中使用 JQuery 所做的那样。如果您对每个待办事项使用 ref ,您仍然可以使用 React 来做到这一点,但这将在系统周围工作,我认为它可能会破坏协调系统?

关于javascript - react 性能: rendering big list with PureRenderMixin,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30976722/

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