0
0
Fork 0

Lazy load toots using IntersectionObserver (#3191)

* refactor(components/status_list): Lazy load using IntersectionObserver

* refactor(components/status_list): Avoid setState bottleneck

* refactor(components/status_list): Update state correctly

* fix(components/status): Render if isIntersecting is undefined

* refactor(components/status): Recycle timeout

* refactor(components/status): Reduce animation duration

* refactor(components/status): Use requestIdleCallback

* chore: Split polyfill bundles

* refactor(components/status_list): Increase rootMargin to 300%

* fix(components/status): Check if onRef is not defined

* chore: Add note about polyfill bundle splitting

* fix(components/status): Reduce animation duration to 0.3 seconds
This commit is contained in:
Sorin Davidoi 2017-05-24 17:55:00 +02:00 committed by Eugen Rochko
parent 676ba50601
commit 8e4d1cba00
8 changed files with 146 additions and 13 deletions

View file

@ -26,6 +26,12 @@ class StatusList extends ImmutablePureComponent {
trackScroll: true,
};
state = {
isIntersecting: [{ }],
}
statusRefQueue = []
handleScroll = (e) => {
const { scrollTop, scrollHeight, clientHeight } = e.target;
const offset = scrollHeight - scrollTop - clientHeight;
@ -42,6 +48,7 @@ class StatusList extends ImmutablePureComponent {
componentDidMount () {
this.attachScrollListener();
this.attachIntersectionObserver();
}
componentDidUpdate (prevProps) {
@ -52,6 +59,39 @@ class StatusList extends ImmutablePureComponent {
componentWillUnmount () {
this.detachScrollListener();
this.detachIntersectionObserver();
}
attachIntersectionObserver () {
const onIntersection = (entries) => {
this.setState(state => {
const isIntersecting = { };
entries.forEach(entry => {
const statusId = entry.target.getAttribute('data-id');
state.isIntersecting[0][statusId] = entry.isIntersecting;
});
return { isIntersecting: [state.isIntersecting[0]] };
});
};
const options = {
root: this.node,
rootMargin: '300% 0px',
};
this.intersectionObserver = new IntersectionObserver(onIntersection, options);
if (this.statusRefQueue.length) {
this.statusRefQueue.forEach(node => this.intersectionObserver.observe(node));
this.statusRefQueue = [];
}
}
detachIntersectionObserver () {
this.intersectionObserver.disconnect();
}
attachScrollListener () {
@ -66,6 +106,15 @@ class StatusList extends ImmutablePureComponent {
this.node = c;
}
handleStatusRef = (node) => {
if (node && this.intersectionObserver) {
const statusId = node.getAttribute('data-id');
this.intersectionObserver.observe(node);
} else {
this.statusRefQueue.push(node);
}
}
handleLoadMore = (e) => {
e.preventDefault();
this.props.onScrollToBottom();
@ -73,10 +122,11 @@ class StatusList extends ImmutablePureComponent {
render () {
const { statusIds, onScrollToBottom, scrollKey, shouldUpdateScroll, isLoading, isUnread, hasMore, prepend, emptyMessage } = this.props;
const isIntersecting = this.state.isIntersecting[0];
let loadMore = '';
let scrollableArea = '';
let unread = '';
let loadMore = null;
let scrollableArea = null;
let unread = null;
if (!isLoading && statusIds.size > 0 && hasMore) {
loadMore = <LoadMore onClick={this.handleLoadMore} />;
@ -95,7 +145,7 @@ class StatusList extends ImmutablePureComponent {
{prepend}
{statusIds.map((statusId) => {
return <StatusContainer key={statusId} id={statusId} />;
return <StatusContainer key={statusId} id={statusId} isIntersecting={isIntersecting[statusId]} onRef={this.handleStatusRef} />;
})}
{loadMore}