Я пытаюсь создать фид сообщений, подобный тому, который есть в instagram (на главной странице).
Я использую Infinite-loader для загрузки, Window-scroller для использования окна в качестве прокрутки, автосайзер для изменения размера списка, как я хочу, и CellMeasurer для измерения «компонента сообщения» один раз после загрузки изображения.
Вот код для компонента списка:
class PostsPartial extends React.PureComponent<IProps>{
state: IPostsPartialState = { posts: [], hasMorePosts: true }
private cache: CellMeasurerCache;
private get rowCount(): number {
return this.state.hasMorePosts ? this.state.posts.length + 1 : this.state.posts.length;
}
constructor(props: IProps) {
super(props);
this.cache = new CellMeasurerCache({
fixedWidth: true,
defaultHeight: 1000
});
this.renderRow = this.renderRow.bind(this);
}
private fetchPosts = ({ startIndex, stopIndex }: { startIndex: number, stopIndex: number }) => {
return getNewPostsChunk(startIndex, stopIndex - startIndex, this.props.token).then((res: IPostsChunkResponse) => {
if (res.success) {
if (res.posts.length === 0) {
// no more posts
this.setState({ hasMorePosts: false })
}
else {
let newPosts = [...this.state.posts, ...res.posts];
this.setState({ posts: newPosts })
}
}
else {
// internal error
}
})
};
private renderRow({ index, key, parent, style }: any) {
return (
<CellMeasurer
cache={this.cache}
columnIndex={0}
key={key}
parent={parent}
rowIndex={index}
>
{({ measure, registerChild }: any) => (
<div className={styles.paddingContainer} ref={registerChild} style={style}>
<Post
isLoaded={this.isRowLoaded({index})}
measure={measure}
post={this.state.posts[index]}
/>
</div>
)}
</CellMeasurer>
);
}
private isRowLoaded = ({ index }: { index: number }) => {
return !!this.state.posts[index];
};
public render() {
return (
<div className={styles.mainContainer}>
<InfiniteLoader
isRowLoaded={this.isRowLoaded}
loadMoreRows={this.fetchPosts}
rowCount={this.rowCount}
>
{({ onRowsRendered, registerChild }: InfiniteLoaderChildProps) => (
<WindowScroller>
{({ height, isScrolling, onChildScroll, scrollTop }) => (
<AutoSizer disableHeight>
{
({ width }: any) => (
<List
ref={registerChild}
onRowsRendered={onRowsRendered}
autoHeight
width={width}
height={height}
isScrolling={isScrolling}
onScroll={onChildScroll}
scrollTop={scrollTop}
deferredMeasurementCache={this.cache}
rowHeight={this.cache.rowHeight}
rowRenderer={this.renderRow}
rowCount={this.rowCount}
overscanRowCount={10}
/>
)
}
</AutoSizer>
)}
</WindowScroller>
)}
</InfiniteLoader>
</div>
);
}
и вот код для компонента сообщения:
const Post:React.FC<IProps> = (props:IProps) => {
if(props.post && props.isLoaded)
return (
<div className={styles.container}>
<Segment className={styles.profileSegmentInternal} attached='top'>
<Image className={styles.verySmallImg} circular size='tiny' src={`${settings.BASE_URL}/feed/photo/user/${props.post.creator}`}></Image>
<Link to={`/profile/${props.post.creator}`}>
<Header size='small' className={styles.headerName} as='span'>{props.post.creator}</Header>
</Link>
</Segment>
<div className={styles.imageContainer}>
<Image onLoad={props.measure} src={`${settings.BASE_URL}/feed/photo/post/${props.post._id}`} className={styles.image}></Image>
</div>
<Segment className={styles.bottomSegment} attached='bottom'>
<>
<Menu className={styles.postMenu}>
<Item className='left'>
<Icon className={styles.iconBtn} size='big' name='heart outline'></Icon>
<Icon className={styles.iconBtn} size='big' name='comment outline'></Icon>
<Icon className={styles.iconBtn} size='big' name='paper plane outline'></Icon>
</Item>
<Item className='right'>
<Icon className={styles.iconBtn} size='big' name='bookmark outline'></Icon>
</Item>
</Menu>
</>
<Header className={styles.likes} size='tiny'>{props.post.likesCount} likes</Header>
<Header className={styles.description} size='tiny'>
<Header size='tiny' className={styles.commentUsername} as='span'>{props.post.creator}</Header>
<Header className={styles.commentText} as='span' size='tiny'> {props.post.description}</Header>
</Header>
<Link to='#'>
<Header className={styles.viewAllComments} size='tiny' disabled>View all comments</Header>
</Link>
{
//backend will return the first 3-4 messeges only
// props.post.messeges.map((messege,index) => (
// ))
}
<Form className={styles.commentForm}>
<Form.Field className={styles.commentField}>
<Form.Input
className={styles.commentInput}
placeholder='Adding comment ...'
>
</Form.Input>
<Button className={styles.commentSubmit} size='medium' primary>Comment</Button>
</Form.Field>
</Form>
</Segment>
</div>
)
else
return (
<p>loading</p>
)
Даже если я удалю все из компонента сообщения и оставлю только изображение, он все равно не будет работать со скоростью более 45-50 кадров в секунду, иногда даже ниже 40 кадров в секунду .
Могу ли я как-то оптимизировать свой подход или я что-то делаю не так? Могу ли я предоставить что-нибудь еще, что может быть полезно?
Заранее благодарю!