frontend: Pagination au scroll
This commit is contained in:
parent
895d0c7f6b
commit
ea13959c91
@ -1,9 +1,9 @@
|
|||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { useState, Fragment } from 'react';
|
import { useState, Fragment, forwardRef } from 'react';
|
||||||
import Loader from '../Loader/Loader';
|
import Loader from '../Loader/Loader';
|
||||||
import './FunctionCard.css';
|
import './FunctionCard.css';
|
||||||
|
|
||||||
const FunctionCard = (props) => {
|
const FunctionCard = forwardRef((props, ref) => {
|
||||||
|
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
|
|
||||||
@ -14,8 +14,9 @@ const FunctionCard = (props) => {
|
|||||||
return (
|
return (
|
||||||
<Link href={`/functions/${props.slug}`}>
|
<Link href={`/functions/${props.slug}`}>
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<div className={"FunctionCard col-sm-24 col-md-10 col-xl-7"}>
|
{/* Elément à une hauteur pendant chargement */}
|
||||||
{isLoading && <Loader width="100px" height="100px" />}
|
<div ref={ref} style={isLoading ? { height: "200px", justifyContent: "center" } : null} className={"FunctionCard col-sm-24 col-md-10 col-xl-7"}>
|
||||||
|
{isLoading && <Loader width="125px" height="125px" />}
|
||||||
<div className={`FunctionCard__container ${isLoading ? "d-none" : ""}`}>
|
<div className={`FunctionCard__container ${isLoading ? "d-none" : ""}`}>
|
||||||
<div className="FunctionCard__top">
|
<div className="FunctionCard__top">
|
||||||
<img onLoad={handleLoad} className="FunctionCard__image" alt={props.title} src={props.image} />
|
<img onLoad={handleLoad} className="FunctionCard__image" alt={props.title} src={props.image} />
|
||||||
@ -31,6 +32,6 @@ const FunctionCard = (props) => {
|
|||||||
</Fragment>
|
</Fragment>
|
||||||
</Link>
|
</Link>
|
||||||
);
|
);
|
||||||
}
|
})
|
||||||
|
|
||||||
export default FunctionCard;
|
export default FunctionCard;
|
@ -1,4 +1,4 @@
|
|||||||
import { Fragment, useState, useEffect } from 'react';
|
import { Fragment, useState, useEffect, useRef, useCallback } from 'react';
|
||||||
import HeadTag from '../components/HeadTag';
|
import HeadTag from '../components/HeadTag';
|
||||||
import FunctionCard from '../components/FunctionCard/FunctionCard';
|
import FunctionCard from '../components/FunctionCard/FunctionCard';
|
||||||
import Loader from '../components/Loader/Loader';
|
import Loader from '../components/Loader/Loader';
|
||||||
@ -18,6 +18,19 @@ const Functions = () => {
|
|||||||
const [isLoadingFunctions, setLoadingFunctions] = useState(true);
|
const [isLoadingFunctions, setLoadingFunctions] = useState(true);
|
||||||
const [pageFunctions, setPageFunctions] = useState(1);
|
const [pageFunctions, setPageFunctions] = useState(1);
|
||||||
|
|
||||||
|
// Permet la pagination au scroll
|
||||||
|
const observer = useRef();
|
||||||
|
const lastFunctionCardRef = useCallback((node) => {
|
||||||
|
if (isLoadingFunctions) return;
|
||||||
|
if (observer.current) observer.current.disconnect();
|
||||||
|
observer.current = new IntersectionObserver((entries) => {
|
||||||
|
if (entries[0].isIntersecting && functionsData.hasMore) {
|
||||||
|
setPageFunctions(pageFunctions + 1);
|
||||||
|
}
|
||||||
|
}, { threshold: 1 });
|
||||||
|
if (node) observer.current.observe(node);
|
||||||
|
}, [isLoadingFunctions, functionsData.hasMore]);
|
||||||
|
|
||||||
const getFunctionsData = () => {
|
const getFunctionsData = () => {
|
||||||
setLoadingFunctions(true);
|
setLoadingFunctions(true);
|
||||||
return new Promise(async (next) => {
|
return new Promise(async (next) => {
|
||||||
@ -40,10 +53,6 @@ const Functions = () => {
|
|||||||
getFunctionsData().then((data) => setFunctionsData(data));
|
getFunctionsData().then((data) => setFunctionsData(data));
|
||||||
}, [inputSearch.selectedCategory, inputSearch.search]);
|
}, [inputSearch.selectedCategory, inputSearch.search]);
|
||||||
|
|
||||||
const loadMore = () => {
|
|
||||||
setPageFunctions(pageFunctions + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleChange = (event) => {
|
const handleChange = (event) => {
|
||||||
const inputSearchNew = { ...inputSearch };
|
const inputSearchNew = { ...inputSearch };
|
||||||
inputSearchNew[event.target.name] = event.target.value;
|
inputSearchNew[event.target.name] = event.target.value;
|
||||||
@ -74,20 +83,15 @@ const Functions = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="row justify-content-center">
|
<div className="row justify-content-center">
|
||||||
{functionsData.rows.map((f) => (
|
{functionsData.rows.map((f, index) => {
|
||||||
<FunctionCard key={f.id} slug={f.slug} image={API_URL + f.image} title={f.title} description={f.description} category={f.categorie} publicationDate={new Date(f.createdAt).toLocaleDateString('fr-FR')} />
|
// Si c'est le dernier élément
|
||||||
))}
|
if (functionsData.rows.length === index + 1) {
|
||||||
</div>
|
return <FunctionCard ref={lastFunctionCardRef} key={f.id} slug={f.slug} image={API_URL + f.image} title={f.title} description={f.description} category={f.categorie} publicationDate={new Date(f.createdAt).toLocaleDateString('fr-FR')} />;
|
||||||
{
|
|
||||||
isLoadingFunctions ?
|
|
||||||
<Loader width="100px" height="100px" />
|
|
||||||
: functionsData.hasMore ?
|
|
||||||
<div className="row justify-content-center">
|
|
||||||
<button className="btn btn-dark" style={{marginBottom: "50px"}} onClick={loadMore}>Charger plus de fonctions ?</button>
|
|
||||||
</div>
|
|
||||||
:
|
|
||||||
null
|
|
||||||
}
|
}
|
||||||
|
return <FunctionCard key={f.id} slug={f.slug} image={API_URL + f.image} title={f.title} description={f.description} category={f.categorie} publicationDate={new Date(f.createdAt).toLocaleDateString('fr-FR')} />;
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
{isLoadingFunctions && <Loader width="100px" height="100px" />}
|
||||||
</div>
|
</div>
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
|
Reference in New Issue
Block a user