├── LICENSE ├── README.md ├── infinite-gif.gif ├── package.json └── src └── index.js /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Prateek Surana 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-native-infinite-looping-scroll 2 | 3 | A react native component that lets you scroll infinitely in both directions by repeating the same items. 4 | 5 |

6 | 7 |

8 | 9 | ## Installation 10 | 11 | Run `npm install react-native-infinite-looping-scroll` in your project directory. 12 | 13 | ## Usage 14 | 15 | This snippet would produce the output shown in the above gif 16 | 17 | ``` 18 | import React, { Component } from 'react'; 19 | import { Platform, StyleSheet, Text, View, FlatList, } from 'react-native'; 20 | import InfiniteScroll from 'react-native-infinite-looping-scroll'; 21 | 22 | 23 | export default class App extends Component { 24 | constructor(props) { 25 | super(props) 26 | } 27 | 28 | render() { 29 | return ( 30 | 31 | {item.key}} 34 | /> 35 | 36 | 37 | ); 38 | } 39 | } 40 | 41 | const styles = StyleSheet.create({ 42 | container: { 43 | flex: 1, 44 | justifyContent: 'center', 45 | alignItems: 'center', 46 | backgroundColor: '#F5FCFF', 47 | }, 48 | listItem: { 49 | flexDirection: 'row', 50 | justifyContent: 'space-between', 51 | alignItems: 'center', 52 | padding: 50, 53 | margin: 2, 54 | borderColor: '#0099A8', 55 | borderWidth: 10, 56 | backgroundColor: '#FEFEFE' 57 | }, 58 | text: { 59 | color: '#0099A8', 60 | fontSize: 32, 61 | fontWeight: 'bold' 62 | }, 63 | welcome: { 64 | fontSize: 20, 65 | textAlign: 'center', 66 | margin: 10, 67 | }, 68 | instructions: { 69 | textAlign: 'center', 70 | color: '#333333', 71 | marginBottom: 5, 72 | }, 73 | }); 74 | 75 | ``` 76 | 77 | ## Props 78 | 79 | It accepts all the [FlatList](https://facebook.github.io/react-native/docs/flatlist.html) props out of which renderItem and data are the compulsory ones and has one more extra prop called `offset` which lets you set the offset at which new data should be added. The default value is 20 and you can change it according to your item. 80 | 81 | ## Pending Tasks 82 | 83 | - [ ] Make upward and downward scroll more smooth. 84 | - [ ] The scroll view should work even when the content size is less than the layout measurement. 85 | 86 | ## Contributing 87 | 88 | This is project is still in beta at the moment, but is still very basic, so if you want to work on the above mention tasks, or you find a bug just open a PR or an issue and ping me! 89 | -------------------------------------------------------------------------------- /infinite-gif.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prateek3255/react-native-infinite-looping-scroll/af1fdcceecbc6430a02e9288838104b8d7091870/infinite-gif.gif -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-infinite-looping-scroll", 3 | "version": "0.0.3", 4 | "description": "A react native component that lets you scroll infinitely in both directions by repeating the same items.", 5 | "main": "src/index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [ 10 | "react-native", 11 | "infinite", 12 | "scroll", 13 | "looping" 14 | ], 15 | "bugs": { 16 | "url": "https://github.com/prateek3255/react-native-infinite-looping-scroll/issues" 17 | }, 18 | "dependencies": { 19 | "prop-types": "15.5.10" 20 | }, 21 | "peerDependencies": { 22 | "react": "^16.0.0-beta.5", 23 | "react-native": "^0.49.1" 24 | }, 25 | "devDependencies": { 26 | "babel-jest": "22.4.4", 27 | "babel-preset-react-native": "4.0.0", 28 | "jest": "22.4.4", 29 | "react-test-renderer": "16.3.1" 30 | }, 31 | "repository": { 32 | "type": "git", 33 | "url": "git+https://github.com/prateek3255/react-native-infinite-looping-scroll.git" 34 | }, 35 | "author": "Prateek Surana ", 36 | "license": "MIT" 37 | } 38 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { FlatList } from 'react-native'; 3 | import PropTypes from 'prop-types' 4 | 5 | export default class InfiniteScroll extends Component { 6 | constructor(props) { 7 | super(props) 8 | this.state = { 9 | data: this.props.data, 10 | end: true, 11 | } 12 | length = this.state.data.length 13 | data = this.state.data.slice() 14 | } 15 | checkScroll({ layoutMeasurement, contentOffset, contentSize }) { 16 | if (this.state.data.length >= length * 3) 17 | this.setState(prevState => ({ 18 | data: prevState.data.slice(length * 2) 19 | })) 20 | 21 | if (contentOffset.y <= this.props.offset) { 22 | this.setState(prevState => ({ 23 | data: [...prevState.data, ...data], 24 | }), () => this.infListRef.scrollToIndex({ index: length, animated: false })) 25 | } 26 | if (layoutMeasurement.height + contentOffset.y >= contentSize.height - this.props.offset && this.state.end) { 27 | this.setState(prevState => ({ 28 | data: [...prevState.data, ...data], 29 | end: false 30 | })) 31 | } 32 | else { 33 | this.setState({ 34 | end: true 35 | }) 36 | } 37 | 38 | } 39 | componentDidMount() { 40 | this.setState(prevState => ({ 41 | data: [...prevState.data, ...prevState.data] 42 | })) 43 | setTimeout(() => { this.infListRef.scrollToIndex({ animated: false, index: length }) }, 500); 44 | 45 | } 46 | render() { 47 | return ( 48 | 49 | { this.infListRef = ref; }} 52 | data={this.state.data} 53 | renderItem={this.props.renderItem} 54 | onScroll={({ nativeEvent }) => this.checkScroll(nativeEvent)} 55 | showsVerticalScrollIndicator={this.props.showsVerticalScrollIndicator} 56 | /> 57 | ); 58 | } 59 | } 60 | 61 | InfiniteScroll.propTypes = { 62 | offset: PropTypes.number, 63 | showsVerticalScrollIndicator: PropTypes.bool 64 | } 65 | 66 | InfiniteScroll.defaultProps = { 67 | offset: 20, 68 | showsVerticalScrollIndicator: false 69 | }; --------------------------------------------------------------------------------