upd: caching data
Deskripsi: - update caching pada fitur utama -yg fitur divisi belom
This commit is contained in:
@@ -2,14 +2,14 @@ import BorderBottomItem from "@/components/borderBottomItem";
|
||||
import InputSearch from "@/components/inputSearch";
|
||||
import SkeletonContent from "@/components/skeletonContent";
|
||||
import Text from '@/components/Text';
|
||||
import { ColorsStatus } from "@/constants/ColorsStatus";
|
||||
import Styles from "@/constants/Styles";
|
||||
import { apiGetAnnouncement } from "@/lib/api";
|
||||
import { useAuthSession } from "@/providers/AuthProvider";
|
||||
import { useTheme } from "@/providers/ThemeProvider";
|
||||
import { MaterialIcons } from "@expo/vector-icons";
|
||||
import { useInfiniteQuery } from "@tanstack/react-query";
|
||||
import { router } from "expo-router";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { RefreshControl, View, VirtualizedList } from "react-native";
|
||||
import { useSelector } from "react-redux";
|
||||
|
||||
@@ -20,68 +20,60 @@ type Props = {
|
||||
createdAt: string
|
||||
}
|
||||
|
||||
|
||||
export default function Announcement() {
|
||||
const { token, decryptToken } = useAuthSession()
|
||||
const { colors } = useTheme();
|
||||
const [data, setData] = useState<Props[]>([])
|
||||
const [search, setSearch] = useState('')
|
||||
const update = useSelector((state: any) => state.announcementUpdate)
|
||||
const [loading, setLoading] = useState(true)
|
||||
const arrSkeleton = Array.from({ length: 5 }, (_, index) => index)
|
||||
const [page, setPage] = useState(1)
|
||||
const [waiting, setWaiting] = useState(false)
|
||||
const [refreshing, setRefreshing] = useState(false)
|
||||
|
||||
async function handleLoad(loading: boolean, thisPage: number) {
|
||||
try {
|
||||
setWaiting(true)
|
||||
setLoading(loading)
|
||||
setPage(thisPage)
|
||||
// TanStack Query Infinite Query
|
||||
const {
|
||||
data,
|
||||
fetchNextPage,
|
||||
hasNextPage,
|
||||
isFetchingNextPage,
|
||||
isLoading,
|
||||
refetch,
|
||||
isRefetching
|
||||
} = useInfiniteQuery({
|
||||
queryKey: ['announcements', search],
|
||||
queryFn: async ({ pageParam = 1 }) => {
|
||||
const hasil = await decryptToken(String(token?.current))
|
||||
const response = await apiGetAnnouncement({ user: hasil, search: search, page: thisPage })
|
||||
if (thisPage == 1) {
|
||||
setData(response.data)
|
||||
} else if (thisPage > 1 && response.data.length > 0) {
|
||||
setData([...data, ...response.data])
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
} finally {
|
||||
setLoading(false)
|
||||
setWaiting(false)
|
||||
}
|
||||
}
|
||||
const response = await apiGetAnnouncement({
|
||||
user: hasil,
|
||||
search: search,
|
||||
page: pageParam
|
||||
})
|
||||
return response.data
|
||||
},
|
||||
initialPageParam: 1,
|
||||
getNextPageParam: (lastPage, allPages) => {
|
||||
return lastPage.length > 0 ? allPages.length + 1 : undefined
|
||||
},
|
||||
})
|
||||
|
||||
// Trigger refetch when Redux state 'update' changes
|
||||
useEffect(() => {
|
||||
handleLoad(false, 1)
|
||||
}, [update])
|
||||
refetch()
|
||||
}, [update, refetch])
|
||||
|
||||
useEffect(() => {
|
||||
handleLoad(true, 1)
|
||||
}, [search])
|
||||
// Flatten data from pages
|
||||
const flattenedData = useMemo(() => {
|
||||
return data?.pages.flat() || []
|
||||
}, [data])
|
||||
|
||||
const loadMoreData = () => {
|
||||
if (waiting) return
|
||||
setTimeout(() => {
|
||||
handleLoad(false, page + 1)
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
const handleRefresh = async () => {
|
||||
setRefreshing(true)
|
||||
handleLoad(false, 1)
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
setRefreshing(false)
|
||||
if (hasNextPage && !isFetchingNextPage) {
|
||||
fetchNextPage()
|
||||
}
|
||||
};
|
||||
|
||||
const getItem = (_data: unknown, index: number): Props => ({
|
||||
id: data[index].id,
|
||||
title: data[index].title,
|
||||
desc: data[index].desc,
|
||||
createdAt: data[index].createdAt,
|
||||
id: flattenedData[index].id,
|
||||
title: flattenedData[index].title,
|
||||
desc: flattenedData[index].desc,
|
||||
createdAt: flattenedData[index].createdAt,
|
||||
})
|
||||
|
||||
return (
|
||||
@@ -91,18 +83,18 @@ export default function Announcement() {
|
||||
</View>
|
||||
<View style={[Styles.flex2, Styles.mt05]}>
|
||||
{
|
||||
loading ?
|
||||
isLoading && !flattenedData.length ?
|
||||
arrSkeleton.map((item, index) => {
|
||||
return (
|
||||
<SkeletonContent key={index} />
|
||||
)
|
||||
})
|
||||
:
|
||||
data.length > 0
|
||||
flattenedData.length > 0
|
||||
?
|
||||
<VirtualizedList
|
||||
data={data}
|
||||
getItemCount={() => data.length}
|
||||
data={flattenedData}
|
||||
getItemCount={() => flattenedData.length}
|
||||
getItem={getItem}
|
||||
renderItem={({ item, index }: { item: Props, index: number }) => {
|
||||
return (
|
||||
@@ -112,9 +104,7 @@ export default function Announcement() {
|
||||
borderType="bottom"
|
||||
bgColor="transparent"
|
||||
icon={
|
||||
// <View style={[Styles.iconContent]}>
|
||||
<MaterialIcons name="campaign" size={25} color={colors.text} />
|
||||
// </View>
|
||||
}
|
||||
title={item.title}
|
||||
desc={item.desc.replace(/<[^>]*>?/gm, '').replace(/\r?\n|\r/g, ' ')}
|
||||
@@ -122,14 +112,14 @@ export default function Announcement() {
|
||||
/>
|
||||
)
|
||||
}}
|
||||
keyExtractor={(item, index) => String(index)}
|
||||
keyExtractor={(item, index) => String(item.id || index)}
|
||||
onEndReached={loadMoreData}
|
||||
onEndReachedThreshold={0.5}
|
||||
showsVerticalScrollIndicator={false}
|
||||
refreshControl={
|
||||
<RefreshControl
|
||||
refreshing={refreshing}
|
||||
onRefresh={handleRefresh}
|
||||
refreshing={isRefetching && !isFetchingNextPage}
|
||||
onRefresh={refetch}
|
||||
tintColor={colors.icon}
|
||||
/>
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user