From 50fb56362ccdfbf8840bd7207081444cf7e9920c Mon Sep 17 00:00:00 2001 From: Yvonnick FRIN Date: Mon, 6 Jan 2020 15:38:20 +0100 Subject: [PATCH] :sparkles: Expose internal methods using ref (#38) --- README.md | 59 ++++++++++++++++++ example/src/App.js | 23 ++++++- src/index.js | 152 +++++++++++++++++++++++++++------------------ 3 files changed, 174 insertions(+), 60 deletions(-) diff --git a/README.md b/README.md index f8e300f..9385148 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,65 @@ function Example({ items, fetchMore, hasMore }) { | loadMoreItems | no | function | A function that will be called each time the list need to load more items. | | placeholder | no | node | Any render-able value like strings or React.Nodes to be displayed while `children` is loading | | customScrollbar | no | boolean | A boolean that determines if [react-custom-scrollbars](https://github.com/malte-wessel/react-custom-scrollbars) is used instead of native one | +| ref | no | ref or function | A ref or a callback ref to get component instance so you can call instance's methods (see [Methods section](/README.md#methods)) | + +## Methods + +**scrollTo(scrollOffset: number): void** + +see [FixedSizeList](https://react-window.now.sh/#/api/FixedSizeList) methods section. + +**scrollToItem(index: number, align: string = "auto"): void** + +see [FixedSizeList](https://react-window.now.sh/#/api/FixedSizeList) methods section. + +**resetloadMoreItemsCache(): void** + +Clear previously loaded items from cache. + +example +```jsx +import React from 'react' + +import InfiniteLoading from 'react-simple-infinite-loading' + +function Example({ items, fetchMore, hasMore }) { + const ref = React.useRef() + const scrollToTop = () => { + if (ref.current) { + ref.current.scrollTo(0) + } + } + const scrollTo50 = () => { + if (ref.current) { + ref.current.scrollToItem(50) + } + } + const resetCache = () => { + if (ref.current) { + ref.current.resetloadMoreItemsCache() + } + } + + return ( + <> + + + +
+ + {items.map(item =>
{item}
)} +
+
+ + ) +} +``` ## License diff --git a/example/src/App.js b/example/src/App.js index 1250ca5..2524824 100644 --- a/example/src/App.js +++ b/example/src/App.js @@ -1,8 +1,24 @@ -import React, { useState } from 'react' +import React, { useState, useRef } from 'react' import InfiniteLoading from 'react-simple-infinite-loading' export default function App() { const [items, setItems] = useState([...Array(100)].map((_, index) => index)) + const ref = useRef() + const scrollToTop = () => { + if (ref.current) { + ref.current.scrollTo(0) + } + } + const scrollTo50 = () => { + if (ref.current) { + ref.current.scrollToItem(50) + } + } + const resetCache = () => { + if (ref.current) { + ref.current.resetloadMoreItemsCache() + } + } const loadMoreItems = () => { const newItems = [...Array(100)].map((_, index) => items.length + index) @@ -19,11 +35,16 @@ export default function App() {

React simple infinite loading example

+ + +

Start scrolling here :

{items.map(item =>
{item}
)}
diff --git a/src/index.js b/src/index.js index 56041b3..c683439 100644 --- a/src/index.js +++ b/src/index.js @@ -1,4 +1,4 @@ -import React, { forwardRef } from 'react' +import React, { Component, createRef } from 'react' import PropTypes from 'prop-types' import { FixedSizeList as List } from 'react-window' @@ -10,60 +10,104 @@ const CustomScrollbarsVirtualList = React.forwardRef((props, ref) => ( )) -const InfiniteLoading = forwardRef(( - { - children, - hasMoreItems, - itemsCount, - itemHeight, - loadMoreItems, - placeholder, - customScrollbar - }, - ref -) => { - let effectiveCount = itemsCount - if (effectiveCount === undefined) { - effectiveCount = hasMoreItems ? children.length + 1 : children.length +class InfiniteLoading extends Component { + static propTypes = { + hasMoreItems: PropTypes.bool, + loadMoreItems: PropTypes.func, + itemsCount: PropTypes.number, + children: PropTypes.array.isRequired, + itemHeight: PropTypes.number.isRequired, + placeholder: PropTypes.node, + customScrollbar: PropTypes.bool } - const isItemLoaded = index => !hasMoreItems || index < children.length + constructor(props) { + super(props) + this.infiniteLoaderRef = createRef() + this.fixedSizeListRef = null + } - return ( - - {({ height, width }) => ( - - {({ onItemsRendered, ref }) => ( - - {({ index, style }) => ( -
- {children[index] != null ? children[index] : placeholder} -
- )} -
- )} -
- )} -
- ) -}) + resetloadMoreItemsCache() { + if (this.infiniteLoaderRef.current) { + this.infiniteLoaderRef.current.resetloadMoreItemsCache() + } else { + throw Error('The InfiniteLoader component is not mounted yet') + } + } + + scrollTo(...args) { + if (this.fixedSizeListRef) { + this.fixedSizeListRef.scrollTo(...args) + } else { + throw Error('The FixedSizeList component is not mounted yet') + } + } + + scrollToItem(...args) { + if (this.fixedSizeListRef) { + this.fixedSizeListRef.scrollToItem(...args) + } else { + throw Error('The FixedSizeList component is not mounted yet') + } + } + + render() { + const { + children, + hasMoreItems, + itemsCount, + itemHeight, + loadMoreItems, + placeholder, + customScrollbar + } = this.props + + let effectiveCount = itemsCount + if (effectiveCount === undefined) { + effectiveCount = hasMoreItems ? children.length + 1 : children.length + } + + const isItemLoaded = index => !hasMoreItems || index < children.length + + return ( + + {({ height, width }) => ( + + {({ onItemsRendered, ref: setListRef }) => ( + { + this.fixedSizeListRef = listRef + setListRef(listRef) + }} + width={width} + outerElementType={customScrollbar ? CustomScrollbarsVirtualList : null} + > + {({ index, style }) => ( +
+ {children[index] != null ? children[index] : placeholder} +
+ )} +
+ )} +
+ )} +
+ ) + } +} CustomScrollbars.propTypes = { onScroll: PropTypes.func.isRequired, - forwardedRef: PropTypes.node.isRequired, + forwardedRef: PropTypes.func.isRequired, style: PropTypes.object.isRequired, children: PropTypes.node.isRequired } @@ -88,14 +132,4 @@ function CustomScrollbars ({ onScroll, forwardedRef, style, children }) { ) } -InfiniteLoading.propTypes = { - hasMoreItems: PropTypes.bool, - loadMoreItems: PropTypes.func, - itemsCount: PropTypes.number, - children: PropTypes.array.isRequired, - itemHeight: PropTypes.number.isRequired, - placeholder: PropTypes.node, - customScrollbar: PropTypes.bool -} - export default InfiniteLoading