1- import React , { Component } from ' react' ;
2- import PropTypes from ' prop-types' ;
1+ import React , { Component } from " react" ;
2+ import PropTypes from " prop-types" ;
33import throttle from './utils/throttle' ;
44
55export default class InfiniteScroll extends Component {
6- constructor ( props ) {
6+ constructor ( props ) {
77 super ( ) ;
88 this . state = {
99 showLoader : false ,
@@ -20,37 +20,43 @@ export default class InfiniteScroll extends Component {
2020 this . maxPullDownDistance = 0 ;
2121
2222 this . onScrollListener = this . onScrollListener . bind ( this ) ;
23- this . throttledOnScrollListener = throttle ( this . onScrollListener , 150 ) . bind ( this ) ;
23+ this . throttledOnScrollListener = throttle ( this . onScrollListener , 150 ) . bind (
24+ this
25+ ) ;
2426 this . onStart = this . onStart . bind ( this ) ;
2527 this . onMove = this . onMove . bind ( this ) ;
2628 this . onEnd = this . onEnd . bind ( this ) ;
29+ this . getScrollableTarget = this . getScrollableTarget . bind ( this ) ;
2730 }
2831
29- componentDidMount ( ) {
30- this . el = this . props . height ? this . _infScroll : this . props . scrollableTarget || window ;
31- this . el . addEventListener ( 'scroll' , this . throttledOnScrollListener ) ;
32+ componentDidMount ( ) {
33+ this . _scrollableNode = this . getScrollableTarget ( ) ;
34+ this . el = this . props . height
35+ ? this . _infScroll
36+ : this . _scrollableNode || window ;
37+ this . el . addEventListener ( "scroll" , this . throttledOnScrollListener ) ;
3238
3339 if (
34- typeof this . props . initialScrollY === ' number' &&
40+ typeof this . props . initialScrollY === " number" &&
3541 this . el . scrollHeight > this . props . initialScrollY
3642 ) {
3743 this . el . scrollTo ( 0 , this . props . initialScrollY ) ;
3844 }
3945
4046 if ( this . props . pullDownToRefresh ) {
41- this . el . addEventListener ( ' touchstart' , this . onStart ) ;
42- this . el . addEventListener ( ' touchmove' , this . onMove ) ;
43- this . el . addEventListener ( ' touchend' , this . onEnd ) ;
47+ this . el . addEventListener ( " touchstart" , this . onStart ) ;
48+ this . el . addEventListener ( " touchmove" , this . onMove ) ;
49+ this . el . addEventListener ( " touchend" , this . onEnd ) ;
4450
45- this . el . addEventListener ( ' mousedown' , this . onStart ) ;
46- this . el . addEventListener ( ' mousemove' , this . onMove ) ;
47- this . el . addEventListener ( ' mouseup' , this . onEnd ) ;
51+ this . el . addEventListener ( " mousedown" , this . onStart ) ;
52+ this . el . addEventListener ( " mousemove" , this . onMove ) ;
53+ this . el . addEventListener ( " mouseup" , this . onEnd ) ;
4854
4955 // get BCR of pullDown element to position it above
5056 this . maxPullDownDistance = this . _pullDown . firstChild . getBoundingClientRect ( ) . height ;
5157 this . forceUpdate ( ) ;
5258
53- if ( typeof this . props . refreshFunction !== ' function' ) {
59+ if ( typeof this . props . refreshFunction !== " function" ) {
5460 throw new Error (
5561 `Mandatory prop "refreshFunction" missing.
5662 Pull Down To Refresh functionality will not work
@@ -60,22 +66,21 @@ export default class InfiniteScroll extends Component {
6066 }
6167 }
6268
63- componentWillUnmount ( ) {
64- this . el . removeEventListener ( ' scroll' , this . throttledOnScrollListener ) ;
69+ componentWillUnmount ( ) {
70+ this . el . removeEventListener ( " scroll" , this . throttledOnScrollListener ) ;
6571
6672 if ( this . props . pullDownToRefresh ) {
67- this . el . removeEventListener ( ' touchstart' , this . onStart ) ;
68- this . el . removeEventListener ( ' touchmove' , this . onMove ) ;
69- this . el . removeEventListener ( ' touchend' , this . onEnd ) ;
73+ this . el . removeEventListener ( " touchstart" , this . onStart ) ;
74+ this . el . removeEventListener ( " touchmove" , this . onMove ) ;
75+ this . el . removeEventListener ( " touchend" , this . onEnd ) ;
7076
71- this . el . removeEventListener ( ' mousedown' , this . onStart ) ;
72- this . el . removeEventListener ( ' mousemove' , this . onMove ) ;
73- this . el . removeEventListener ( ' mouseup' , this . onEnd ) ;
77+ this . el . removeEventListener ( " mousedown" , this . onStart ) ;
78+ this . el . removeEventListener ( " mousemove" , this . onMove ) ;
79+ this . el . removeEventListener ( " mouseup" , this . onEnd ) ;
7480 }
7581 }
7682
77- componentWillReceiveProps ( props ) {
78-
83+ componentWillReceiveProps ( props ) {
7984 // do nothing when dataLength is unchanged
8085 if ( this . props . dataLength === props . dataLength ) return ;
8186
@@ -87,25 +92,39 @@ export default class InfiniteScroll extends Component {
8792 } ) ;
8893 }
8994
90- onStart ( evt ) {
95+ getScrollableTarget ( ) {
96+ if ( this . props . scrollableTarget instanceof HTMLElement ) return this . props . scrollableTarget ;
97+ if ( typeof this . props . scrollableTarget === 'string' ) {
98+ return document . getElementById ( this . props . scrollableTarget ) ;
99+ }
100+ if ( this . props . scrollableTarget === null ) {
101+ console . warn ( `You are trying to pass scrollableTarget but it is null. This might
102+ happen because the element may not have been added to DOM yet.
103+ See https://github.com/ankeetmaini/react-infinite-scroll-component/issues/59 for more info.
104+ ` ) ;
105+ }
106+ return null ;
107+ }
108+
109+ onStart ( evt ) {
91110 if ( this . state . lastScrollTop ) return ;
92111
93112 this . dragging = true ;
94113 this . startY = evt . pageY || evt . touches [ 0 ] . pageY ;
95114 this . currentY = this . startY ;
96115
97- this . _infScroll . style . willChange = ' transform' ;
116+ this . _infScroll . style . willChange = " transform" ;
98117 this . _infScroll . style . transition = `transform 0.2s cubic-bezier(0,0,0.31,1)` ;
99118 }
100119
101- onMove ( evt ) {
120+ onMove ( evt ) {
102121 if ( ! this . dragging ) return ;
103122 this . currentY = evt . pageY || evt . touches [ 0 ] . pageY ;
104123
105124 // user is scrolling down to up
106125 if ( this . currentY < this . startY ) return ;
107126
108- if ( ( this . currentY - this . startY ) >= this . props . pullDownToRefreshThreshold ) {
127+ if ( this . currentY - this . startY >= this . props . pullDownToRefreshThreshold ) {
109128 this . setState ( {
110129 pullToRefreshThresholdBreached : true
111130 } ) ;
@@ -114,11 +133,12 @@ export default class InfiniteScroll extends Component {
114133 // so you can drag upto 1.5 times of the maxPullDownDistance
115134 if ( this . currentY - this . startY > this . maxPullDownDistance * 1.5 ) return ;
116135
117- this . _infScroll . style . overflow = 'visible' ;
118- this . _infScroll . style . transform = `translate3d(0px, ${ this . currentY - this . startY } px, 0px)` ;
136+ this . _infScroll . style . overflow = "visible" ;
137+ this . _infScroll . style . transform = `translate3d(0px, ${ this . currentY -
138+ this . startY } px, 0px)`;
119139 }
120140
121- onEnd ( evt ) {
141+ onEnd ( evt ) {
122142 this . startY = 0 ;
123143 this . currentY = 0 ;
124144
@@ -129,29 +149,36 @@ export default class InfiniteScroll extends Component {
129149 }
130150
131151 requestAnimationFrame ( ( ) => {
132- this . _infScroll . style . overflow = ' auto' ;
133- this . _infScroll . style . transform = ' none' ;
134- this . _infScroll . style . willChange = ' none' ;
152+ this . _infScroll . style . overflow = " auto" ;
153+ this . _infScroll . style . transform = " none" ;
154+ this . _infScroll . style . willChange = " none" ;
135155 } ) ;
136156 }
137157
138- isElementAtBottom ( target , scrollThreshold = 0.8 ) {
139- const clientHeight = ( target === document . body || target === document . documentElement )
140- ? window . screen . availHeight : target . clientHeight ;
158+ isElementAtBottom ( target , scrollThreshold = 0.8 ) {
159+ const clientHeight =
160+ target === document . body || target === document . documentElement
161+ ? window . screen . availHeight
162+ : target . clientHeight ;
141163
142- return ( target . scrollTop + clientHeight ) >= scrollThreshold * target . scrollHeight ;
164+ return (
165+ target . scrollTop + clientHeight >= scrollThreshold * target . scrollHeight
166+ ) ;
143167 }
144168
145- onScrollListener ( event ) {
146- if ( typeof this . props . onScroll === ' function' ) {
169+ onScrollListener ( event ) {
170+ if ( typeof this . props . onScroll === " function" ) {
147171 // Execute this callback in next tick so that it does not affect the
148172 // functionality of the library.
149173 setTimeout ( ( ) => this . props . onScroll ( event ) , 0 ) ;
150174 }
151175
152- let target = this . props . height || this . props . scrollableTarget
153- ? event . target
154- : ( document . documentElement . scrollTop ? document . documentElement : document . body ) ;
176+ let target =
177+ this . props . height || this . _scrollableNode
178+ ? event . target
179+ : document . documentElement . scrollTop
180+ ? document . documentElement
181+ : document . body ;
155182
156183 // return immediately if the action has already been triggered,
157184 // prevents multiple triggers.
@@ -161,43 +188,49 @@ export default class InfiniteScroll extends Component {
161188
162189 // call the `next` function in the props to trigger the next data fetch
163190 if ( atBottom && this . props . hasMore ) {
164- this . setState ( { actionTriggered : true , showLoader : true } ) ;
191+ this . setState ( { actionTriggered : true , showLoader : true } ) ;
165192 this . props . next ( ) ;
166193 }
167- this . setState ( { lastScrollTop : target . scrollTop } ) ;
194+ this . setState ( { lastScrollTop : target . scrollTop } ) ;
168195 }
169196
170- render ( ) {
197+ render ( ) {
171198 const style = {
172- height : this . props . height || ' auto' ,
173- overflow : ' auto' ,
174- WebkitOverflowScrolling : ' touch' ,
199+ height : this . props . height || " auto" ,
200+ overflow : " auto" ,
201+ WebkitOverflowScrolling : " touch" ,
175202 ...this . props . style
176203 } ;
177- const hasChildren = this . props . hasChildren || ! ! ( this . props . children && this . props . children . length ) ;
204+ const hasChildren =
205+ this . props . hasChildren ||
206+ ! ! ( this . props . children && this . props . children . length ) ;
178207
179208 // because heighted infiniteScroll visualy breaks
180209 // on drag down as overflow becomes visible
181- const outerDivStyle = ( this . props . pullDownToRefresh && this . props . height )
182- ? { overflow : 'auto' } : { } ;
210+ const outerDivStyle =
211+ this . props . pullDownToRefresh && this . props . height
212+ ? { overflow : "auto" }
213+ : { } ;
183214 return (
184215 < div style = { outerDivStyle } >
185216 < div
186- className = ' infinite-scroll-component'
187- ref = { infScroll => this . _infScroll = infScroll }
217+ className = " infinite-scroll-component"
218+ ref = { infScroll => ( this . _infScroll = infScroll ) }
188219 style = { style }
189220 >
190221 { this . props . pullDownToRefresh && (
191222 < div
192- style = { { position : ' relative' } }
193- ref = { pullDown => this . _pullDown = pullDown }
223+ style = { { position : " relative" } }
224+ ref = { pullDown => ( this . _pullDown = pullDown ) }
194225 >
195- < div style = { {
196- position : 'absolute' ,
197- left : 0 ,
198- right : 0 ,
199- top : ( - 1 * this . maxPullDownDistance ) ,
200- } } >
226+ < div
227+ style = { {
228+ position : "absolute" ,
229+ left : 0 ,
230+ right : 0 ,
231+ top : - 1 * this . maxPullDownDistance
232+ } }
233+ >
201234 { ! this . state . pullToRefreshThresholdBreached &&
202235 this . props . pullDownToRefreshContent }
203236 { this . state . pullToRefreshThresholdBreached &&
@@ -206,7 +239,9 @@ export default class InfiniteScroll extends Component {
206239 </ div >
207240 ) }
208241 { this . props . children }
209- { ! this . state . showLoader && ! hasChildren && this . props . hasMore &&
242+ { ! this . state . showLoader &&
243+ ! hasChildren &&
244+ this . props . hasMore &&
210245 this . props . loader }
211246 { this . state . showLoader && this . props . hasMore && this . props . loader }
212247 { ! this . props . hasMore && this . props . endMessage }
@@ -221,7 +256,7 @@ InfiniteScroll.defaultProps = {
221256 releaseToRefreshContent : < h3 > Release to refresh</ h3 > ,
222257 pullDownToRefreshThreshold : 100 ,
223258 disableBrowserPullToRefresh : true
224- }
259+ } ;
225260
226261InfiniteScroll . propTypes = {
227262 next : PropTypes . func ,
@@ -240,5 +275,5 @@ InfiniteScroll.propTypes = {
240275 pullDownToRefreshThreshold : PropTypes . number ,
241276 refreshFunction : PropTypes . func ,
242277 onScroll : PropTypes . func ,
243- dataLength : PropTypes . number . isRequired ,
278+ dataLength : PropTypes . number . isRequired
244279} ;
0 commit comments