Skip to content

Commit

Permalink
Adds dynamic classes and child props
Browse files Browse the repository at this point in the history
  • Loading branch information
Davide Curletti committed Apr 5, 2016
1 parent 3f6971c commit b9d113a
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 31 deletions.
16 changes: 10 additions & 6 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,12 @@ npm install redux-infinite-scroll --save

## Usage

In order to use it in your React app, simply import it and follow the example below. The component expects the items
prop to receive an array of React components that it then renders to the DOM. The `loadMore` prop
expects a function that updates the Redux store with more items and therefore causes React to re-render the component.
In order to use it in your React app, simply import it and follow the example below. The component expects to receive
child elements that it then injects into the DOM. The `loadMore` prop expects a function that requests for more
items to be loaded once the container/window has reached the bottom `threshold`. If there are no more items left to
be passed to the component, make sure to set the `hasMore` prop to be `false`. **Important** If you are using
an element as the scrollable component, rather than the window, you MUST pass a fixed height to the `containerHeight`
prop.

##### ES6 format

Expand Down Expand Up @@ -94,14 +97,15 @@ function chatReducer(state=initialState, action=undefined) {
| elementIsScrollable | bool | no | true | Defines whether the div will have a fixed height and listens to the div's overflow event or instead have a non-fixed height and listen to the window scroll event
| containerHeight | integer or string | no | '100%' | Sets an inline style on the height of the topmost div.
| threshold | integer | no | 100 | The number of pixels
| hasMore | bool | no | true | Whether there are more items waiting to be displayed
| hasMore | bool | no | true | Whether there are more items waiting to be displayed. Set this to false once all of the items have been passed down to either `items` or `children`.
| loadingMore | bool | no |false| A prop that should be set to `true` by the parent component whenever the `loadMore` function gets invoked, and then toggled to `false` once that function has finished updating the `items` prop.
| loader | any | no| Loading... | The value of this prop gets injected as the last element of the parent div when `hasMore` `loadingMore` and `showLoader` are all `true`.
| showLoader | bool | true | | Whether to show the loader when the `loadingMore` property is `true`
| showLoader | bool | false | true | Whether to show the loader when the `loadingMore` property is `true`
| loadMore | function | yes |undefined| The function is called when the component has reached the `threshold` and `hasMore` is true.
| items | array |yes|undefined| The array of elements waiting to be rendered. Normally each item in the array is a React component.
| holderType | string |no|div| The type the loader is rendered as, could be `ul`, `dl`, etc.
| className | string |no|''| Any additional classes to be added to the holder.
| items | array || Immutable List |no|[]| The array of elements waiting to be rendered. Use either this or `children`. **Deprecated.**
| children | array || Immutable List |no| [] | The array of elements waiting to be rendered. Use either this or `items`.

## Credits

Expand Down
23 changes: 22 additions & 1 deletion dist/redux-infinite-scroll.min.js

Large diffs are not rendered by default.

43 changes: 33 additions & 10 deletions lib/ReduxInfiniteScroll.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ var _reactDom = require('react-dom');

var _reactDom2 = _interopRequireDefault(_reactDom);

var _reactImmutableProptypes = require('react-immutable-proptypes');

var _reactImmutableProptypes2 = _interopRequireDefault(_reactImmutableProptypes);

var _DOMPositionUtils = require('./Utilities/DOMPositionUtils');

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
Expand Down Expand Up @@ -87,17 +91,18 @@ var ReduxInfiniteScroll = function (_Component) {
var _this2 = this;

// This is to prevent the upcoming logic from toggling a load more before
// redux has passed any data to the component
// any data has been passed to the component
if (this.props.items <= 0) return;

// Need to find better way around this setTimeout
setTimeout(function () {
var bottomPosition = _this2.props.elementIsScrollable ? _this2._elScrollListener() : _this2._windowScrollListener();

if (bottomPosition < Number(_this2.props.threshold)) {
_this2.detachScrollListener();
_this2.props.loadMore();
}
}, 0);
});
}
}, {
key: 'detachScrollListener',
Expand All @@ -106,6 +111,13 @@ var ReduxInfiniteScroll = function (_Component) {
el.removeEventListener('scroll', this.scrollFunction, true);
el.removeEventListener('resize', this.scrollFunction, true);
}
}, {
key: '_renderOptions',
value: function _renderOptions() {
var allItems = this.props.children.concat(this.props.items);

return [allItems, this.renderLoader()];
}
}, {
key: 'componentWillUnmount',
value: function componentWillUnmount() {
Expand All @@ -116,17 +128,23 @@ var ReduxInfiniteScroll = function (_Component) {
value: function renderLoader() {
return this.props.loadingMore && this.props.showLoader ? this.props.loader : undefined;
}
}, {
key: '_assignHolderClass',
value: function _assignHolderClass() {
var additionalClass = void 0;
additionalClass = typeof this.props.className === 'function' ? this.props.className() : this.props.className;

return 'redux-infinite-scroll ' + additionalClass;
}
}, {
key: 'render',
value: function render() {
var Holder = this.props.holderType;

return _react2.default.createElement(
Holder,
{ className: 'rs-infinite-scroll', style: { height: this.props.containerHeight } },
this.props.items.map(function (item, i) {
return item;
}),
this.renderLoader()
{ className: this._assignHolderClass(), style: { height: this.props.containerHeight } },
this._renderOptions()
);
}
}]);
Expand All @@ -146,11 +164,14 @@ ReduxInfiniteScroll.propTypes = {
loader: _react2.default.PropTypes.any,
showLoader: _react2.default.PropTypes.bool,
loadMore: _react2.default.PropTypes.func.isRequired,
items: _react2.default.PropTypes.array.isRequired,
holderType: _react2.default.PropTypes.string
items: _react2.default.PropTypes.oneOfType([_reactImmutableProptypes2.default.list, _react2.default.PropTypes.array]),
children: _react2.default.PropTypes.oneOfType([_reactImmutableProptypes2.default.list, _react2.default.PropTypes.array]),
holderType: _react2.default.PropTypes.string,
className: _react2.default.PropTypes.oneOfType([_react2.default.PropTypes.string, _react2.default.PropTypes.func])
};

ReduxInfiniteScroll.defaultProps = {
className: '',
elementIsScrollable: true,
containerHeight: '100%',
threshold: 100,
Expand All @@ -162,5 +183,7 @@ ReduxInfiniteScroll.defaultProps = {
'Loading...'
),
showLoader: true,
holderType: 'div'
holderType: 'div',
children: [],
items: []
};
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "redux-infinite-scroll",
"version": "1.0.2",
"version": "1.0.4",
"description": "React infinite scroll component designed for a Redux data-flow.",
"main": "lib/ReduxInfiniteScroll.js",
"scripts": {
Expand Down Expand Up @@ -50,8 +50,10 @@
"webpack-hot-middleware": "^2.6.0"
},
"dependencies": {
"immutable": "^3.7.6",
"lodash": "~3.1.0",
"react": "^0.14.6",
"react-dom": "^0.14.6",
"lodash": "~3.1.0"
"react-immutable-proptypes": "^1.7.0"
}
}
49 changes: 37 additions & 12 deletions src/ReduxInfiniteScroll.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import React, { Component } from 'react';
import ReactDOM from 'react-dom';

import ImmutablePropTypes from 'react-immutable-proptypes';

import {topPosition} from './Utilities/DOMPositionUtils';

export default class ReduxInfiniteScroll extends Component {
Expand Down Expand Up @@ -51,17 +53,18 @@ export default class ReduxInfiniteScroll extends Component {

scrollListener() {
// This is to prevent the upcoming logic from toggling a load more before
// redux has passed any data to the component
// any data has been passed to the component
if (this.props.items <= 0) return;

// Need to find better way around this setTimeout
setTimeout(() => {
let bottomPosition = this.props.elementIsScrollable ? this._elScrollListener() : this._windowScrollListener();

if (bottomPosition < Number(this.props.threshold)) {
this.detachScrollListener();
this.props.loadMore();
}
}, 0);
});
}

detachScrollListener () {
Expand All @@ -70,6 +73,12 @@ export default class ReduxInfiniteScroll extends Component {
el.removeEventListener('resize', this.scrollFunction, true);
}

_renderOptions() {
const allItems = this.props.children.concat(this.props.items);

return [allItems, this.renderLoader()];
}

componentWillUnmount () {
this.detachScrollListener();
}
Expand All @@ -78,17 +87,20 @@ export default class ReduxInfiniteScroll extends Component {
return (this.props.loadingMore && this.props.showLoader) ? this.props.loader : undefined;
}

_assignHolderClass() {
let additionalClass;
additionalClass = (typeof this.props.className === 'function') ? this.props.className() : this.props.className;

return 'redux-infinite-scroll ' + additionalClass;
}

render () {
const Holder = this.props.holderType;
const className = "rs-infinite-scroll " + this.props.className;

return (
<Holder className={ className } style={{height: this.props.containerHeight}}>
{this.props.items.map((item, i) => {
return item;
})}
{this.renderLoader()}
</Holder>
<Holder className={ this._assignHolderClass() } style={{height: this.props.containerHeight}}>
{this._renderOptions()}
</Holder>
)
}
}
Expand All @@ -105,8 +117,19 @@ ReduxInfiniteScroll.propTypes = {
loader: React.PropTypes.any,
showLoader: React.PropTypes.bool,
loadMore: React.PropTypes.func.isRequired,
items: React.PropTypes.array.isRequired,
holderType: React.PropTypes.string
items: React.PropTypes.oneOfType([
ImmutablePropTypes.list,
React.PropTypes.array
]),
children: React.PropTypes.oneOfType([
ImmutablePropTypes.list,
React.PropTypes.array
]),
holderType: React.PropTypes.string,
className: React.PropTypes.oneOfType([
React.PropTypes.string,
React.PropTypes.func
])
};

ReduxInfiniteScroll.defaultProps = {
Expand All @@ -118,5 +141,7 @@ ReduxInfiniteScroll.defaultProps = {
loadingMore: false,
loader: <div style={{textAlign: 'center'}}>Loading...</div>,
showLoader: true,
holderType: 'div'
holderType: 'div',
children: [],
items: []
};

0 comments on commit b9d113a

Please sign in to comment.