From bf52e7385bc0cbb5d40d51f770cc40c81fd6315e Mon Sep 17 00:00:00 2001 From: mathysPaul Date: Sun, 12 Nov 2023 23:39:27 +0100 Subject: [PATCH] [FEAT] MusicList component: Implemented MusicList for displaying music items with optimized rendering and dynamic loading. --- front/components/UI/MusicList.tsx | 231 ++++++++++++++++-------------- front/views/MusicView.tsx | 58 +++----- 2 files changed, 142 insertions(+), 147 deletions(-) diff --git a/front/components/UI/MusicList.tsx b/front/components/UI/MusicList.tsx index b4beace..a15ef2b 100644 --- a/front/components/UI/MusicList.tsx +++ b/front/components/UI/MusicList.tsx @@ -1,11 +1,10 @@ -import { FlatList, HStack, View, useBreakpointValue, useTheme, Text, Row } from "native-base"; -import MusicItem, { MusicItemType } from "./MusicItem"; -import React, { useState } from "react"; -import { ActivityIndicator } from "react-native"; -import { ArrowDown2, ArrowRotateLeft, Chart2, Cup, Icon } from "iconsax-react-native"; -import { StyleSheet } from 'react-native'; -import ButtonBase from "./ButtonBase"; -import useColorScheme from "../../hooks/colorScheme"; +import React, { useCallback, useState, useMemo } from 'react'; +import { FlatList, HStack, View, useBreakpointValue, useTheme, Text, Row } from 'native-base'; +import { ActivityIndicator, StyleSheet } from 'react-native'; +import MusicItem, { MusicItemType } from './MusicItem'; +import ButtonBase from './ButtonBase'; +import { ArrowDown2, Chart2, ArrowRotateLeft, Cup, Icon } from 'iconsax-react-native'; +import useColorScheme from '../../hooks/colorScheme'; interface MusicItemTitleProps { text: string; @@ -13,123 +12,145 @@ interface MusicItemTitleProps { isBigScreen: boolean; } -const MusicItemTitle = (props: MusicItemTitleProps) => { - const colorScheme = useColorScheme(); +const MusicItemTitle = React.memo((props: MusicItemTitleProps) => { + const colorScheme = useColorScheme(); - return ( - - {props.isBigScreen && ( - - {props.text} - - )} - - - ); -}; + return ( + + {props.isBigScreen && ( + + {props.text} + + )} + + + ); +}); type MusicListProps = { initialMusics: MusicItemType[]; - loadMoreMusics: (page: number) => Promise; // fonction pour charger plus de musiques + loadMoreMusics: (page: number, musics: MusicItemType[]) => Promise; + musicsPerPage: number; }; -const MusicList: React.FC = ({initialMusics}) => { - const [musicData, setMusicData] = useState(initialMusics); - const [loading, setLoading] = useState(false); - const { colors } = useTheme(); - const screenSize = useBreakpointValue({ base: 'small', md: 'md', xl: 'xl' }); - const isSmallScreen = screenSize === 'small'; - const isBigScreen = screenSize === 'xl'; +const MusicList: React.FC = React.memo(({ initialMusics, loadMoreMusics, musicsPerPage }) => { + const [musicListState, setMusicListState] = useState({ + allMusics: initialMusics, + displayedMusics: initialMusics.slice(0, musicsPerPage), + currentPage: 1, + loading: false, + hasMoreMusics: true, + }); + const { colors } = useTheme(); + const screenSize = useBreakpointValue({ base: 'small', md: 'md', xl: 'xl' }); + const isBigScreen = screenSize === 'xl'; - const loadMoreMusicItems = () => { - if (!loading) { - setLoading(true); - setTimeout(() => { - const moreItems: MusicItemType[] = [ - ]; - setMusicData((currentItems) => [...currentItems, ...moreItems]); - setLoading(false); - }, 2000); // Simule un appel réseau avec un délai de 2 secondes. - } - }; - - return ( - - - - - Song - - {[ - { text: 'level', icon: Chart2 }, - { text: 'lastScore', icon: ArrowRotateLeft }, - { text: 'BastScore', icon: Cup }, - ].map((value) => ( - - ))} - - } - keyExtractor={(item) => item.artist + item.song} + const loadMoreMusicItems = useCallback(async () => { + if (musicListState.loading || !musicListState.hasMoreMusics) { + return; + } + + setMusicListState(prevState => ({ ...prevState, loading: true })); + + let hasMoreMusics = true; + const nextEndIndex = (musicListState.currentPage + 1) * musicsPerPage; + let updatedAllMusics = musicListState.allMusics; + + if (updatedAllMusics.length <= nextEndIndex) { + const newMusics = await loadMoreMusics(musicListState.currentPage, updatedAllMusics); + updatedAllMusics = [...updatedAllMusics, ...newMusics]; + hasMoreMusics = newMusics.length > 0; + } + + setMusicListState(prevState => ({ + ...prevState, + allMusics: updatedAllMusics, + displayedMusics: updatedAllMusics.slice(0, nextEndIndex), + currentPage: prevState.currentPage + 1, + loading: false, + hasMoreMusics: hasMoreMusics, + })); + }, [musicsPerPage, loadMoreMusics, musicListState]); + + const headerComponent = useMemo(() => ( + + + Song + + {[ + { text: 'level', icon: Chart2 }, + { text: 'lastScore', icon: ArrowRotateLeft }, + { text: 'BastScore', icon: Cup }, + ].map((value) => ( + - - - {loading ? ( - + ))} + + ), [colors.coolGray[500], isBigScreen]); + + return ( + } + keyExtractor={(item) => item.artist + item.song} + ListFooterComponent={musicListState.hasMoreMusics ? + ( + {musicListState.loading ? ( + ) : ( )} - - - ); -}; + ) : null + } + /> + ); +}); const styles = StyleSheet.create({ - container: { + container: { flex: 1, gap: 2, borderRadius: 10, overflow: 'hidden', - }, - footerContainer : { + }, + footerContainer : { height: 60, justifyContent: 'center', alignItems: 'center', - } + } }); -export default MusicList; \ No newline at end of file +export default MusicList; diff --git a/front/views/MusicView.tsx b/front/views/MusicView.tsx index dc3cd0a..2f09649 100644 --- a/front/views/MusicView.tsx +++ b/front/views/MusicView.tsx @@ -169,49 +169,23 @@ export const fakeMusicData = [ export const FavoritesMusic = () => { - const { colors } = useTheme(); - const screenSize = useBreakpointValue({ base: 'small', md: 'md', xl: 'xl' }); - const isSmallScreen = screenSize === 'small'; - const isBigScreen = screenSize === 'xl'; - return ( - <> - { - console.log(page, 'Function not implemented.'); - return []; - }} - /> - {/* { - console.log('Liked !'); - }} - level={3} - lastScore={25550} - bestScore={420} - artist={'Ludwig van Beethoven'} - song={'Piano Sonata No. 8'} - /> - { - console.log('Liked !'); - }} - level={3} - lastScore={255500000} - bestScore={42000} - artist={'Ludwig van Beethoven'} - song={'Sonata for Piano no. 20 in G major, op. 49 no. 2'} - /> */} - + { + console.log(page, 'Loading more musics.'); + + // Calculer le début et la fin de la tranche à charger + const startIndex = musics.length; + const endIndex = startIndex + 15; + console.log('length:', fakeMusicData.length); + console.log('min:', Math.min(endIndex, fakeMusicData.length)); + let tmp = fakeMusicData.slice(startIndex, Math.min(endIndex, fakeMusicData.length)); + console.log('tmp:', tmp.length); + return tmp; + }} + /> ); };