forked from ankeetmaini/react-infinite-scroll-component
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 1b7d93c
Showing
16 changed files
with
22,253 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
|
||
.DS_Store | ||
.idea | ||
node_modules |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
/.gitignore | ||
/.npmignore | ||
/demos/ | ||
/server.js | ||
/webpack.* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
# react-infinite-scroll | ||
A component to make all your infinite scrolling woes go away with just 4.15 kB! | ||
|
||
# install | ||
```bash | ||
npm install --save react-infinite-scroll-component | ||
``` | ||
|
||
# demos | ||
The code for demos is in the `demos/` directory. Open `lib/index.html` in your browser to see the demos in action. | ||
|
||
# using | ||
The `InfiniteScroll` component can be used in two ways. | ||
|
||
- Without giving any height to your **scrollable** content. In which case the scroll will happen at `document.body` like *Facebook's* timeline scroll. | ||
- If you want your **scrollable** content to have a definite height then your content will be scrollable with the height specified in the props. | ||
|
||
```js | ||
<InfiniteScroll | ||
next={functionToLoadNextData} | ||
hasMore={true} | ||
loader={<h4>Loading...</h4>}> | ||
{items} // your long array goes in here | ||
</InfiniteScroll> | ||
``` | ||
# props | ||
name | type | description | ||
-----|------|------------ | ||
**next** | function | a function which must be called after reaching the bottom. It must trigger some sort of action which fetches the next data. **The data is passed as `children` to the `InfiniteScroll` component and the data should contain previous items too.** e.g. *Initial data = [1, 2, 3]* and then next load of data should be *[1, 2, 3, 4, 5, 6]*. | ||
**hasMore** | boolean | it tells the InfiniteScroll component on whether to call `next` function on reaching the bottom and shows an `endMessage` to the user | ||
**children** | node (list) | the data items which you need to scroll. | ||
**loader** | node | you can send a loader component to show while the component waits for the next load of data. e.g. `<h3>Loading...</h3>` or any fancy loader element | ||
**scrollThreshold** | number | a threshold value after that the InfiniteScroll will call `next`. By default it's `0.8`. It means the `next` will be called when the user comes below 80% of the total height. | ||
**endMessage** | node | this message is shown to the user when he has seen all the records which means he's at the bottom and `hasMore` is `false` | ||
**style** | object | any style which you want to override | ||
**height** | number | optional, give only if you want to have a fixed height scrolling content | ||
**hasChildren** | bool | `children` is by default assumed to be of type array and it's length is used to determine if loader needs to be shown or not, if your `children` is not an array, specify this prop to tell if your items are 0 or more. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
import React, {Component, PropTypes} from 'react'; | ||
import debounce from './utils/debounce'; | ||
|
||
export default class InfiniteScroll extends Component { | ||
constructor (props) { | ||
super(); | ||
this.state = { | ||
showLoader: false, | ||
lastScrollTop: 0, | ||
actionTriggered: false | ||
}; | ||
this.onScrollListener = this.onScrollListener.bind(this); | ||
this.debouncedOnScrollListener = debounce(this.onScrollListener, 150).bind(this); | ||
} | ||
|
||
componentDidMount () { | ||
this.el = this.props.height ? this.refs.infScroll : window; | ||
this.el.addEventListener('scroll', this.debouncedOnScrollListener); | ||
} | ||
|
||
componentWillUnMount () { | ||
this.el.removeEventListener('scroll', this.debouncedOnScrollListener); | ||
} | ||
|
||
componentWillReceiveProps (props) { | ||
// new data was sent in | ||
this.setState({ | ||
showLoader: false, | ||
actionTriggered: false | ||
}); | ||
} | ||
|
||
isElementAtBottom (target, scrollThreshold = 0.8) { | ||
const scrolled = scrollThreshold * (target.scrollHeight - target.scrollTop); | ||
const {clientHeight} = target; | ||
return scrolled < clientHeight; | ||
} | ||
|
||
onScrollListener (event) { | ||
let target = this.props.height | ||
? event.target | ||
: (document.documentElement.scrollTop ? document.documentElement : document.body); | ||
|
||
// if user scrolls up, remove action trigger lock | ||
if (target.scrollTop < this.state.lastScrollTop) { | ||
this.setState({ | ||
actionTriggered: false, | ||
lastScrollTop: target.scrollTop | ||
}); | ||
return; // user's going up, we don't care | ||
} | ||
|
||
// return immediately if the action has already been triggered, | ||
// prevents multiple triggers. | ||
if (this.state.actionTriggered) return; | ||
|
||
let atBottom = this.isElementAtBottom(target, this.props.scrollThreshold); | ||
|
||
// call the `next` function in the props to trigger the next data fetch | ||
if (atBottom && this.props.hasMore) { | ||
this.props.next(); | ||
this.setState({actionTriggered: true, showLoader: true}); | ||
} | ||
this.setState({lastScrollTop: target.scrollTop}); | ||
} | ||
|
||
render () { | ||
const style = { | ||
height: this.props.height || 'auto', | ||
overflow: 'auto' | ||
}; | ||
const hasChildren = this.props.hasChildren || !!(this.props.children && this.props.children.length); | ||
return ( | ||
<div className='infinite-scroll-component' ref='infScroll' | ||
style={style}> | ||
{this.props.children} | ||
{!this.state.showLoader && !hasChildren && this.props.hasMore && | ||
this.props.loader} | ||
{this.state.showLoader && this.props.loader} | ||
{!this.props.hasMore && ( | ||
<p style={{textAlign: 'center'}}> | ||
{this.props.endMessage || <b>Yay! You have seen it all</b>} | ||
</p> | ||
)} | ||
</div> | ||
); | ||
} | ||
} | ||
|
||
InfiniteScroll.propTypes = { | ||
next: PropTypes.func, | ||
hasMore: PropTypes.bool, | ||
children: PropTypes.node, | ||
loader: PropTypes.node.isRequired, | ||
scrollThreshold: PropTypes.number, | ||
endMessage: PropTypes.node, | ||
style: PropTypes.object, | ||
height: PropTypes.number, | ||
hasChildren: PropTypes.bool | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
export default function debounce (func, wait) { | ||
let timeout; | ||
return function () { | ||
const _this = this; | ||
const args = arguments; | ||
|
||
const later = function () { | ||
timeout = null; | ||
func.apply(_this, args); | ||
}; | ||
clearTimeout(timeout); | ||
timeout = setTimeout(later, wait); | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import React from 'react'; | ||
import ReactDOM from 'react-dom'; | ||
|
||
import InfiniteScroll from '../app'; | ||
|
||
const divs = [ | ||
<div key={1} style={{height: 200, background: 'cornsilk'}}>Big div no 1</div>, | ||
<div key={2} style={{height: 200, background: 'cornsilk'}}>Big div no 2</div>, | ||
<div key={3} style={{height: 200, background: 'cornsilk'}}>Big div no 3</div>, | ||
<div key={4} style={{height: 200, background: 'cornsilk'}}>Big div no 4</div>, | ||
<div key={5} style={{height: 200, background: 'cornsilk'}}>Big div no 5</div> | ||
]; | ||
|
||
const heightMessage = 'Infinite Scroll given fixed height of 300px in props'; | ||
|
||
export default class Height extends React.Component { | ||
constructor () { | ||
super(); | ||
this.state = {divs: divs}; | ||
this.generateDivs = this.generateDivs.bind(this); | ||
} | ||
|
||
generateDivs () { | ||
let moreDivs = []; | ||
let count = this.state.divs.length; | ||
for (let i = 0; i < 10; i++) { | ||
moreDivs.push( | ||
<div key={'div' + count++} style={{background: 'cornsilk'}}> | ||
Div no {count} | ||
</div> | ||
); | ||
} | ||
setTimeout(() => { | ||
this.setState({divs: this.state.divs.concat(moreDivs)}); | ||
}, 500); | ||
} | ||
|
||
render () { | ||
return ( | ||
<div> | ||
<h3>{heightMessage}</h3> | ||
<InfiniteScroll | ||
next={this.generateDivs} | ||
hasMore={true} | ||
height={300} | ||
loader={<h4>Loading...</h4>}> | ||
{this.state.divs} | ||
</InfiniteScroll> | ||
</div> | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import React from 'react'; | ||
import ReactDOM from 'react-dom'; | ||
|
||
import Height from './height'; | ||
import NoHeight from './no-height'; | ||
|
||
|
||
const toggle = function () { | ||
var mode = 'noHeight'; | ||
return () => { | ||
if (mode === 'noHeight') { | ||
mode = 'height'; | ||
ReactDOM.render(<Height/>, document.getElementById('app')); | ||
} else { | ||
mode = 'noHeight'; | ||
ReactDOM.render(<NoHeight/>, document.getElementById('app')); | ||
} | ||
}; | ||
}(); | ||
|
||
ReactDOM.render( | ||
<button onClick={toggle}>Toggle between Height and No Height versions</button>, | ||
document.getElementById('button') | ||
); | ||
|
||
// initial render | ||
ReactDOM.render(<NoHeight/>, document.getElementById('app')); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import React from 'react'; | ||
import ReactDOM from 'react-dom'; | ||
|
||
import InfiniteScroll from '../app'; | ||
|
||
const divs = [ | ||
<div key={1} style={{height: 200, background: 'cornsilk'}}>Big div no 1</div>, | ||
<div key={2} style={{height: 200, background: 'cornsilk'}}>Big div no 2</div>, | ||
<div key={3} style={{height: 200, background: 'cornsilk'}}>Big div no 3</div>, | ||
<div key={4} style={{height: 200, background: 'cornsilk'}}>Big div no 4</div>, | ||
<div key={5} style={{height: 200, background: 'cornsilk'}}>Big div no 5</div> | ||
]; | ||
|
||
const noHeightMessage = 'No height given to InfiniteScroll, free scroll like Facebook'; | ||
|
||
export default class NoHeight extends React.Component { | ||
constructor () { | ||
super(); | ||
this.state = { | ||
divs: divs | ||
}; | ||
this.generateDivs = this.generateDivs.bind(this); | ||
} | ||
|
||
generateDivs () { | ||
let moreDivs = []; | ||
let count = this.state.divs.length; | ||
for (let i = 0; i < 10; i++) { | ||
moreDivs.push( | ||
<div key={'div' + count++} style={{background: 'cornsilk'}}> | ||
Div no {count} | ||
</div> | ||
); | ||
} | ||
setTimeout(() => { | ||
this.setState({divs: this.state.divs.concat(moreDivs)}); | ||
}, 500); | ||
} | ||
|
||
render () { | ||
return ( | ||
<div> | ||
<h3>{noHeightMessage}</h3> | ||
<InfiniteScroll | ||
next={this.generateDivs} | ||
hasMore={true} | ||
loader={<h4>Loading...</h4>}> | ||
{this.state.divs} | ||
</InfiniteScroll> | ||
</div> | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<title>Infinite-Scroll</title> | ||
<meta charset="utf-8"> | ||
<style> | ||
#noHeight, #height { | ||
float: left; | ||
width: 50%; | ||
} | ||
</style> | ||
</head> | ||
<body> | ||
<h1>Infinite Scroll Demo</h1> | ||
<div id="button"></div> | ||
<div id="app"></div> | ||
</body> | ||
</html> |
Oops, something went wrong.