gpt4 book ai didi

javascript - React-virtualized WindowScroller 性能问题

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

我正在使用 react 虚拟化库来创建高效的新闻提要。图书馆很棒。我组合了 WindowScroller、AutoSizer 和 VirtualScroll 组件以实现无限滚动行为。问题是,当我手动设置 VirtualScroll 高度并且不使用 WindowScroller 时,所有浏览器的性能都很好。但是,当我添加 WindowScroller 组件时,性能显着降低,尤其是在 Firefox (v47.0) 中。我该如何优化它以便可以使用窗口滚动?

这是新闻组件,其中使用了react-virtualized,我有两种类型的列表项 - 标题项和简单项,标题项包含一组新闻的日期,因此它有点长。

import React, { PropTypes, Component } from 'react';
import Divider from 'material-ui/Divider';
import Subheader from 'material-ui/Subheader';
import { Grid, Row, Col } from 'react-flexbox-grid';
import NewsItem from '../NewsItem';
import styles from './styles.css';
import CircularProgress from 'material-ui/CircularProgress';
import Paper from 'material-ui/Paper';
import classNames from 'classnames';
import { InfiniteLoader, WindowScroller, AutoSizer, VirtualScroll } from 'react-virtualized';
import shallowCompare from 'react-addons-shallow-compare';

class News extends Component {

componentDidMount() {
this.props.onFetchPage(0);
}

shouldComponentUpdate(nextProps, nextState) {
return shallowCompare(this, nextProps, nextState);
}

getRowHeight({ index }) {
const elementHeight = 200;
const headerHeight = 78;
if (!this.isRowLoaded(index)) {
return elementHeight;
}
return this.props.articles[index].isHeader ?
headerHeight + elementHeight : elementHeight;
}

displayElement(article, isScrolling) {
return (
<Paper
key={article.id}
className={classNames(styles.newsItemContainer, {
[styles.scrolling]: isScrolling
})}
>
<NewsItem {...article} />
<Divider />
</Paper>
);
}

isRowLoaded(index) {
return !this.props.hasNextPage || index < this.props.articles.length;
}

renderRow(index, isScrolling) {
if (!this.isRowLoaded(index)) {
return (
<div className={styles.spinnerContainer}>
{this.props.isFetching ? <CircularProgress /> : null}
</div>
);
}
const { isHeader, date, article } = this.props.articles[index];
if (isHeader) {
return (
<div>
<Subheader
key={date}
className={styles.groupHeader}
>
{date}
</Subheader>
{this.displayElement(article, isScrolling)}
</div>
);
}
return this.displayElement(article, isScrolling);
}

noRowsRenderer() {
return (<p>No articles found</p>);
}

render() {
const {
articles,
onFetchPage,
pageNumber,
isFetching,
hasNextPage
} = this.props;

const loadMoreRows = isFetching ?
() => {} :
() => onFetchPage(pageNumber + 1);

const rowCount = hasNextPage ? articles.length + 1 : articles.length;

return (
<Grid>
<Row>
<Col xs={12} sm={8} smOffset={2}>
<InfiniteLoader
isRowLoaded={({ index }) => this.isRowLoaded(index)}
loadMoreRows={loadMoreRows}
rowCount={rowCount}
>
{({ onRowsRendered, registerChild, isScrolling }) => (
<WindowScroller>
{({ height, scrollTop }) => (
<AutoSizer disableHeight>
{({ width }) => (
<VirtualScroll
autoHeight
ref={registerChild}
height={height}
rowCount={rowCount}
rowHeight={(...args) => this.getRowHeight(...args)}
rowRenderer={({ index }) => this.renderRow(index, isScrolling)}
width={width}
noRowsRenderer={this.noRowsRenderer}
onRowsRendered={onRowsRendered}
overscanRowCount={10}
scrollTop={scrollTop}
/>
)}
</AutoSizer>
)}
</WindowScroller>
)}
</InfiniteLoader>
</Col>
</Row>
</Grid>
);
}
}

News.propTypes = {
articles: PropTypes.array.isRequired,
onFetchPage: PropTypes.func.isRequired,
isFetching: PropTypes.bool.isRequired,
pageNumber: PropTypes.number.isRequired,
hasNextPage: PropTypes.bool.isRequired
};

export default News;

列表项是以下组件:

import React, { PropTypes } from 'react';
import styles from './styles.css';
import { Row, Col } from 'react-flexbox-grid';
import shallowCompare from 'react-addons-shallow-compare';
import pick from 'lodash/pick';
import NewsItemContent from '../NewsItemContent';

class NewsItem extends React.Component {

shouldComponentUpdate(nextProps, nextState) {
return shallowCompare(this, nextProps, nextState);
}

render() {
const contentProps = pick(this.props, [
'title', 'description', 'seedUrl', 'seedCode', 'date'
]);
return (
<div
onClick={() => window.open(this.props.url, '_blank')}
className={styles.newsItem}
>
{this.props.imageUrl ?
<Row>
<Col xs={3}>
<div
role="presentation"
style={{ backgroundImage: `url(${this.props.imageUrl})` }}
className={styles.previewImage}
/>
</Col>
<Col xs={9}>
<NewsItemContent {...contentProps} />
</Col>
</Row> :
<Row>
<Col xs={12}>
<NewsItemContent {...contentProps} />
</Col>
</Row>
}
</div>
);
}
}

NewsItem.propTypes = {
imageUrl: PropTypes.string,
description: PropTypes.string.isRequired,
title: PropTypes.string.isRequired,
url: PropTypes.string.isRequired,
date: PropTypes.object.isRequired,
seedUrl: PropTypes.string.isRequired,
seedCode: PropTypes.string.isRequired
};

export default NewsItem;

这里的NewsItemContent是一个简单的纯组件,没有任何逻辑,这里就不放了。

谢谢!

更新:我在 Firefox 中记录了窗口滚动和 block 滚动的性能时间表:

最佳答案

我认为这与 React setState() 调用有关。

WindowScroller 监听 window 对象的滚动事件。这些发生在 React 的知识之外,因此 setState() 调用由同步的 ReactDefaultBatchingStrategy 处理。 Grid 是一个 React 组件,因此它的 onScroll 事件发生在 React 的感知范围内。由此发生的 setState() 调用可以通过 ReactUpdateQueue 更智能地进行批处理。

查看您共享的时间线,对 Grid 滚动事件的 setState 调用由 ReactUpdateQueue 排队。但是看看 WindowScroller 时间线 - 帧速率最差的地方,其 setState() 调用立即传递到 ReactDefaultBatchingStrategy。

关于javascript - React-virtualized WindowScroller 性能问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38641018/

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