Refactor to use Scrollbars from FancyScrollbar.

pull/2427/head
Hunter Trujillo 2017-12-05 12:09:01 -07:00
parent 49a47e71a3
commit ae32aba01f
1 changed files with 55 additions and 24 deletions

View File

@ -1,28 +1,30 @@
import React, {Component, PropTypes} from 'react' import React, {Component, PropTypes} from 'react'
import classnames from 'classnames'
import {Scrollbars} from 'react-custom-scrollbars'
import _ from 'lodash'
const {arrayOf, number, shape, string} = PropTypes const {arrayOf, number, shape, string} = PropTypes
class InfiniteScroll extends Component { class InfiniteScroll extends Component {
scrollElement // Cache values from Scrollbars events that need to be independent of render
// Cache values that need to be independent of
// Should not be setState as need not trigger a re-render // Should not be setState as need not trigger a re-render
scrollTop = 0 scrollbarsScrollTop = 0
containerHeight = 0 scrollbarsClientHeight = 0
state = { state = {
topIndex: 0, topIndex: 0,
bottomIndex: 0, bottomIndex: 0,
topPadding: 0, topPadding: 0,
bottomPadding: 0, bottomPadding: 0,
windowHeight: window.innerHeight,
} }
windowing = (props, state) => { windowing = (props, state) => {
const {itemHeight, items} = props const {itemHeight, items} = props
const {bottomIndex} = state const {bottomIndex} = state
const itemDistance = Math.round(this.scrollTop / itemHeight) const itemDistance = Math.round(this.scrollbarsScrollTop / itemHeight)
const itemCount = Math.round(this.containerHeight / itemHeight) + 1 const itemCount = Math.round(this.scrollbarsClientHeight / itemHeight) + 1
// If state is the same, do not setState to the same value multiple times. // If state is the same, do not setState to the same value multiple times.
// Improves performance and prevents errors. // Improves performance and prevents errors.
@ -42,27 +44,42 @@ class InfiniteScroll extends Component {
}) })
} }
handleScroll = evt => { handleScroll = ({clientHeight, scrollTop}) => {
if (evt.target === this.scrollElement) { let shouldUpdate = false
this.scrollTop = evt.target.scrollTop
if (
(typeof clientHeight !== 'undefined' &&
this.scrollbarsClientHeight !== clientHeight) ||
(typeof scrollTop !== 'undefined' &&
this.scrollbarsScrollTop !== scrollTop)
) {
shouldUpdate = true
}
this.scrollbarsClientHeight = clientHeight
this.scrollbarsScrollTop = scrollTop
if (shouldUpdate) {
this.windowing(this.props, this.state) this.windowing(this.props, this.state)
} }
} }
throttledHandleScroll = _.throttle(this.handleScroll, 100)
handleResize = () => { handleResize = () => {
this.containerHeight = this.scrollElement.clientHeight this.setState({windowHeight: window.innerHeight})
} }
componentDidMount() { throttledHandleResize = _.throttle(this.handleResize, 100)
this.containerHeight = this.scrollElement.clientHeight
this.windowing(this.props, this.state)
window.addEventListener('scroll', this.handleScroll, true) handleMakeDiv = className => props =>
<div {...props} className={`fancy-scroll--${className}`} />
componentDidMount() {
window.addEventListener('resize', this.handleResize, true) window.addEventListener('resize', this.handleResize, true)
} }
componentWillUnmount() { componentWillUnmount() {
window.removeEventListener('scroll', this.handleScroll, true)
window.removeEventListener('resize', this.handleResize, true) window.removeEventListener('resize', this.handleResize, true)
} }
@ -73,20 +90,34 @@ class InfiniteScroll extends Component {
render() { render() {
const {className, items} = this.props const {className, items} = this.props
const {topIndex, bottomIndex, topPadding, bottomPadding} = this.state const {
topIndex,
bottomIndex,
topPadding,
bottomPadding,
windowHeight,
} = this.state
return ( return (
<div <Scrollbars
className={className} className={classnames(className, 'fancy-scroll--container')}
ref={r => (this.scrollElement = r)} autoHide={true}
style={{ autoHideTimeout={1000}
overflowY: 'scroll', autoHideDuration={250}
}} autoHeight={false}
renderTrackHorizontal={this.handleMakeDiv('track-h')}
renderTrackVertical={this.handleMakeDiv('track-v')}
renderThumbHorizontal={this.handleMakeDiv('thumb-h')}
renderThumbVertical={this.handleMakeDiv('thumb-v')}
renderView={this.handleMakeDiv('view')}
onScrollFrame={this.throttledHandleScroll}
onUpdate={this.throttledHandleScroll}
key={windowHeight}
> >
<div style={{height: topPadding}} /> <div style={{height: topPadding}} />
{items.filter((_item, i) => i >= topIndex && i <= bottomIndex)} {items.filter((_item, i) => i >= topIndex && i <= bottomIndex)}
<div style={{height: bottomPadding}} /> <div style={{height: bottomPadding}} />
</div> </Scrollbars>
) )
} }
} }