-
Notifications
You must be signed in to change notification settings - Fork 36
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1407 from cozy/load-more
feat: Load more component
- Loading branch information
Showing
3 changed files
with
90 additions
and
1 deletion.
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
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 @@ | ||
#### Load More | ||
|
||
The Load More component can be used at the bottom of infinite lists where it will automatically start loading the next batch of data when it scrolls into view. | ||
|
||
``` | ||
import LoadMore from 'cozy-ui/transpiled/react/LoadMore'; | ||
initialState = { elements: [1, 2] }; | ||
const sleep = (timeout) => new Promise(resolve => setTimeout(resolve, timeout)) | ||
const fetchMore = async () => { | ||
await sleep(1000); | ||
setState(state => ({ elements: [...state.elements, state.elements.length + 1]})); | ||
} | ||
<div style={{ height: '300px', overflow: 'auto' }}> | ||
<p> | ||
Scroll down to load more. | ||
</p> | ||
{state.elements.map((el, index) => ( | ||
<div style={{ background: 'grey', height: '160px', marginBottom: '10px' }} key={index} /> | ||
))} | ||
{ state.elements.length < 25 && <LoadMore label="Load more" fetchMore={fetchMore} /> } | ||
</div> | ||
``` | ||
|
||
If for some reason the loading doesn't happen automatically, the component displays a button that can be used to manually load the next batch of data. | ||
This next example loads nothing, it's just there to show what the button looks like. | ||
|
||
``` | ||
import LoadMore from 'cozy-ui/transpiled/react/LoadMore'; | ||
<div> | ||
<LoadMore label="Load more" fetchMore={() => {}} /> | ||
</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,51 @@ | ||
import React, { useState, useEffect, useRef, useCallback } from 'react' | ||
import PropTypes from 'prop-types' | ||
import Button from '../Button' | ||
import Spinner from '../Spinner' | ||
|
||
const LoadMore = ({ fetchMore, label }) => { | ||
const [isLoading, setIsLoading] = useState(false) | ||
const elementRef = useRef() | ||
|
||
const startFetchMore = useCallback(async () => { | ||
if (!isLoading) { | ||
setIsLoading(true) | ||
await fetchMore() | ||
setIsLoading(false) | ||
} | ||
}, [isLoading, fetchMore]) | ||
|
||
const checkIntersectionsEntries = intersectionEntries => { | ||
if (intersectionEntries.filter(entry => entry.isIntersecting).length > 0) | ||
startFetchMore() | ||
} | ||
|
||
useEffect(() => { | ||
const observer = new IntersectionObserver(checkIntersectionsEntries) | ||
observer.observe(elementRef.current) | ||
|
||
return () => { | ||
observer.unobserve(elementRef.current) | ||
observer.disconnect() | ||
} | ||
}) | ||
|
||
return ( | ||
<span ref={elementRef}> | ||
<Button | ||
theme="text" | ||
onClick={startFetchMore} | ||
label={isLoading ? <Spinner noMargin /> : label} | ||
/> | ||
</span> | ||
) | ||
} | ||
|
||
LoadMore.propTypes = { | ||
/** A function that is called when the next batch of data needs to be loaded. Can return a promise. */ | ||
fetchMore: PropTypes.func.isRequired, | ||
/** The label for the button */ | ||
label: PropTypes.string.isRequired | ||
} | ||
|
||
export default LoadMore |