├── .gitignore
├── LICENSE
├── README.md
├── index.js
├── package.json
└── src
└── component.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Nicholas Rakoto
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | React Scroll Load Component
2 | =================================
3 |
4 | A dummy React component to implement continuous load on scroll for **modern browser**.
5 |
6 | ### Usage
7 | ```
8 | var ScrollLoad = require('react-component-scrollload');
9 | ```
10 | ```html
11 |
}>
12 | {items}
13 |
14 | ```
15 |
16 | `npm install react-component-scroll --save`
17 |
18 | ### Prop types
19 | ```javascript
20 | propTypes: {
21 | hasMore: React.PropTypes.bool.isRequired, // if there is more to load
22 | loadMore: React.PropTypes.func.isRequired, // callback to load more
23 | isLoading: React.PropTypes.bool.isRequired, // indicate if a loading is ongoing
24 | useDocument: React.PropTypes.bool, // if true, the scrolling is calculated based on the document and not the element, default false
25 | threshold: React.PropTypes.number, // pixel threshold, default 1000
26 | loader: React.PropTypes.component, // displayed loader component, default React.DOM.div(null, 'Loading...')
27 |
28 | // disable pointer to improve scrolling perf
29 | disablePointer: React.PropTypes.number, // ms delay until disablePointerClass class is removed after last scroll event, default 0 (feature disabled)
30 | disablePointerClass: React.PropTypes.string // default class added to child wrapper div, default 'disable-pointer'
31 | }
32 | ```
33 |
34 | #### Scroll performance
35 |
36 | A dummy way to improve scrolling performance.
37 |
38 | Add to your css a `disable-pointer` definition, default name defined by `disablePointerClass`.
39 |
40 | ```css
41 | .disable-pointer {
42 | pointer-events: none !important;
43 | }
44 | ```
45 |
46 | Add `disablePointer` prop with a delay in milliseconds.
47 | ```html
48 | ...
49 | ```
50 |
51 |
52 | ### Licence
53 |
54 | MIT
55 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | module.exports = require('./src/component');
2 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-component-scrollload",
3 | "version": "0.5.1",
4 | "description": "React component to implement continuous load on scroll",
5 | "main": "index.js",
6 | "keywords": ["react", "infinite", "continuous", "scroll", "react-component"],
7 | "scripts": {
8 | "test": "echo \"Error: no test specified\" && exit 1"
9 | },
10 | "repository": {
11 | "type": "git",
12 | "url": "git://github.com/nrako/react-component-scrollload.git"
13 | },
14 | "author": "@nrako",
15 | "license": "MIT",
16 | "dependencies": {
17 | "document-offset": "^1.0.4"
18 | },
19 | "devDependencies": {
20 | "react": "^0.14.0",
21 | "react-dom": "^0.14.0"
22 | },
23 | "peerDependencies": {
24 | "react": ">= 0.14.0",
25 | "react-dom": ">= 0.14.0"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/component.js:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 | var ReactDOM = require('react-dom');
3 | var documentOffset = require('document-offset');
4 |
5 | var ContinuousScroll = React.createClass({
6 | propTypes: {
7 | hasMore: React.PropTypes.bool.isRequired,
8 | loadMore: React.PropTypes.func.isRequired,
9 | isLoading: React.PropTypes.bool.isRequired,
10 | useDocument: React.PropTypes.bool,
11 | threshold: React.PropTypes.number,
12 | loader: React.PropTypes.element,
13 | disablePointer: React.PropTypes.number,
14 | disablePointerClass: React.PropTypes.string
15 | },
16 | getDefaultProps: function () {
17 | return {
18 | threshold: 1000,
19 | loader: React.createElement('div', null, 'Loading...'),
20 | disablePointer: 0,
21 | disablePointerClass: 'disable-pointer'
22 | };
23 | },
24 | disablePointerTimeout: null,
25 | onScroll: function () {
26 | if (!this.isMounted())
27 | return;
28 |
29 | if (this.props.disablePointer > 0)
30 | this.disablePointer();
31 |
32 | if (!this.props.hasMore || this.props.isLoading)
33 | return;
34 |
35 | var el = ReactDOM.findDOMNode(this);
36 | var currentScroll;
37 |
38 | if (this.props.useDocument) {
39 | // See http://stackoverflow.com/a/28633515/564163
40 | currentScroll = (
41 | window.pageYOffset ||
42 | document.documentElement.scrollTop ||
43 | document.body.scrollTop ||
44 | 0
45 | ) + documentOffset(el).top;
46 | } else {
47 | currentScroll = el.scrollTop + el.offsetHeight;
48 | }
49 |
50 | if(currentScroll + this.props.threshold < el.scrollHeight)
51 | return;
52 |
53 | this.props.loadMore();
54 | },
55 | disablePointer: function () {
56 | if (this.disablePointerTimeout === null)
57 | this.refs.wrapper.classList.add(this.props.disablePointerClass);
58 |
59 | clearTimeout(this.disablePointerTimeout);
60 | this.disablePointerTimeout = setTimeout(this.removeDisablePointerClass, this.props.disablePointer);
61 | },
62 | removeDisablePointerClass: function () {
63 | if (this.refs.wrapper)
64 | this.refs.wrapper.classList.remove(this.props.disablePointerClass);
65 |
66 | this.disablePointerTimeout = null;
67 | },
68 | componentDidMount: function () {
69 | this.listenScroll();
70 |
71 | // About setTimeout: fluxxor enforce flux principle; dispatching an action during and action would trigger an error
72 | setTimeout(this.onScroll);
73 | },
74 | componentDidUpdate: function () {
75 | // when component update need to check if loaded children height are bigger than threshold else load more
76 | // About setTimeout: fluxxor enforce flux principle; dispatching an action during and action would trigger an error
77 | setTimeout(this.onScroll);
78 | },
79 | componentWillUnmount: function () {
80 | this.unlistenScroll();
81 | },
82 | listenScroll: function () {
83 | var el = this.props.useDocument ? window : ReactDOM.findDOMNode(this);
84 |
85 | el.addEventListener('scroll', this.onScroll);
86 | window.addEventListener('resize', this.onScroll);
87 | },
88 | unlistenScroll: function () {
89 | var el = this.props.useDocument ? window : ReactDOM.findDOMNode(this);
90 |
91 | el.removeEventListener('scroll', this.onScroll);
92 | window.removeEventListener('resize', this.onScroll);
93 | },
94 | componentWillReceiveProps: function (nextProps) {
95 | // if there is no need to listen on scroll anymore
96 | if (nextProps.hasMore)
97 | this.listenScroll();
98 | else if (this.props.disablePointer <= 0)
99 | this.unlistenScroll();
100 | },
101 | render: function() {
102 | return (
103 | React.createElement('div', this.props,
104 | React.createElement('div', {ref: 'wrapper'},
105 | this.props.children
106 | ),
107 | this.props.isLoading && this.props.loader
108 | )
109 | );
110 | }
111 |
112 | });
113 |
114 | module.exports = ContinuousScroll;
115 |
--------------------------------------------------------------------------------