Refactor to use Scrollbars from FancyScrollbar.
parent
49a47e71a3
commit
ae32aba01f
|
@ -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>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue