У меня есть два компонента: AllBuyErstab и TicketcheckedIntab. TicketcheckedIntab работает нормально, но я испытываю задержку прокрутки в AllBuyErstab. Кто -нибудь может предложить решение? Иногда я получал пустые проблемы с строками, которые я исправил, назначив фиксированную высоту и используя getItemlayout. Тем не менее, проблема прокрутки все еще сохраняется - и удивительно, это происходит только в AllBuyErstab, а не в TicketcheckedIntab < /p>
import React, { useEffect, useState } from 'react';
import {
CHECKIN_MESSAGES,
ERROR_MESSAGE_OVERRIDE,
EVENT_ERROR_MESSAGES,
} from '@/constants/messages';
import {
View,
Text,
StyleSheet,
TouchableOpacity,
ScrollView,
FlatList,
Modal,
ActivityIndicator,
} from 'react-native';
import { router, useLocalSearchParams } from 'expo-router';
import { useDataProvider } from '@/provider/DataProvider';
import {
getAttendeesTicketStatus,
updateCancelledAttendeeTicketStatus,
incrementCheckedCount,
cleanLocalDB,
getLastSyncAt,
insertAttendee,
} from '@/db/sqlite';
import EmptyList from '@/components/EmptyList';
import checkedInDateFormat from '@/utils/checked-in-date-format';
import { useSQLiteContext } from 'expo-sqlite';
import RenderAttendeesStatus from '@/components/RenderAttendeesStatus';
import { Attendee, AttendeeStatus, TicketStatus } from '@/types/types';
import { manualCheckin } from '@/services/api';
import { useBuyers } from '@/hooks/useBuyers';
import eventBus from '@/eventBus';
import { useQueryClient } from '@tanstack/react-query';
const ITEM_HEIGHT = 100;
interface AllBuyersCard {
attendee: any;
errorMessage?: any;
isLoading: any;
handleTryAgain: (orderId: string, datetimeId: string) => void;
handleManualCheckIn: (orderId: string, datetimeId: string) => void;
}
function AllBuyersCard({
attendee,
errorMessage,
isLoading,
handleTryAgain,
handleManualCheckIn,
}: AllBuyersCard) {
console.log("Rendered:", attendee.orderid);
const [modalVisible, setModalVisible] = useState(false);
const showConfirmation = () => {
setModalVisible(true);
};
const handleConfirm = () => {
setModalVisible(false);
handleManualCheckIn(attendee.orderid, attendee.datetime_id);
};
const handleCancel = () => {
setModalVisible(false);
};
return (
{attendee.fname} {attendee.lname}
OrderId #{attendee?.orderid?.slice(-6)}
Qty {attendee.total_qty}
Confirm Check-In
Are you sure you want to check in {attendee.fname}{' '}
{attendee.lname} with Order #
{attendee?.orderid?.slice(-6)}?
Cancel
Yes
);
}
export default function AllBuyersTab() {
const params = useLocalSearchParams();
const db = useSQLiteContext(); /* Database reference */
const queryClient = useQueryClient();
const [isLoading, setIsLoading] = React.useState({});
/* state to fix overlapping issue in rendering attendee list */
const [initialRender, setInitialRender] = React.useState(true);
/* end of overlapping state */
const [errorMessage, setErrorMessage] = React.useState({});
const {
eventData,
eventLabel,
datetimeId,
refetch,
searchQuery,
isOnline,
} = useDataProvider();
const {
buyers,
loading,
hasMore,
loadMore,
refetch: localRefetch,
} = useBuyers(db, eventLabel as string, datetimeId as string, searchQuery);
useEffect(() => {
const listener = () => {
refetch();
localRefetch();
};
eventBus.on('ticketCheckedIn', listener);
eventBus.on('reset', listener);
return () => {
eventBus.off('ticketCheckedIn', listener);
eventBus.off('reset', listener);
};
}, []);
const handleManualCheckIn = async (orderId: string, datetimeId: string) => {
try {
setIsLoading((prev) => ({ ...prev, [orderId]: true }));
setErrorMessage((prev) => ({ ...prev, [orderId]: null }));
// Check if ticket exists locally
const existingTicket = await getAttendeesTicketStatus(
db,
eventData.events.event_id,
orderId,
datetimeId
);
const timestamp = await getLastSyncAt(
db,
eventLabel as string,
datetimeId,
1
);
const eventId = eventData.events.event_id;
if (isOnline) {
if (existingTicket) {
const checkinResult = await manualCheckin({
datetimeId,
orderId,
eventId,
lastSyncTime: timestamp?.lastSyncAt as string,
});
// if refunded_on has date that means we need to save checked_date null
// sync will be true that is 1
/*
* checked Date
* if there is checked_date and it status chk_status not already "1"
* */
// const eventId = eventData.events.event_id;
const basePayload = {
eventId: eventId,
orderId,
datetimeId,
sync: 1,
checkedInDate: checkinResult?.checked_date,
refunded_on: checkinResult?.refunded_on,
canceled_on: checkinResult?.canceled_on,
message: checkinResult?.message,
};
if (
checkinResult.att_detail.status ===
AttendeeStatus.CheckedIn
) {
const payload = {
...basePayload,
chk_status: TicketStatus.CHECKED,
};
await updateCancelledAttendeeTicketStatus(db, payload);
/*
* Note: In case of refunded and canceled users, no need to increment the order checked
* */
// Increment checked
await incrementCheckedCount(db, eventId, datetimeId);
} else if (
checkinResult.att_detail.status ===
AttendeeStatus.Refunded
) {
const payload = {
...basePayload,
chk_status: TicketStatus.UNCHECKED,
};
await updateCancelledAttendeeTicketStatus(db, payload);
} else if (
checkinResult.att_detail.status ===
AttendeeStatus.Canceled
) {
const payload = {
...basePayload,
chk_status: TicketStatus.UNCHECKED,
};
await updateCancelledAttendeeTicketStatus(db, payload);
}
// Emit Event so that we can always have TicketCheckedInTab refresh
eventBus.emit('ticketCheckedIn');
refetch();
localRefetch();
router.replace({
pathname: '/(tabs)/checked-in',
params: {
data: JSON.stringify(checkinResult),
// Below parameters used to redirect the user back on the page form where they came from
datetimeId: params.datetime_id,
dateId: params.date_id,
eventLabel: params.event_label,
},
});
} else {
// if not ticket not exist locally but online
const checkinResult = await manualCheckin({
datetimeId,
orderId,
eventId,
lastSyncTime: timestamp?.lastSyncAt as string,
});
const ALREADY_CHECKED_MESSAGE =
CHECKIN_MESSAGES.ALREADY_CHECKED_IN_MESSAGE;
/* Since we don't have any other way to ensure that the below block run only once
* we are comparing the message, since we need to increment the checked count only once, not every time.
* */
if (
checkinResult.checked_date &&
checkinResult.message !== ALREADY_CHECKED_MESSAGE
) {
/*
* Note: Do i need to use transaction here think about it.
* */
await incrementCheckedCount(db, eventId, datetimeId);
const { ticket_quantity: total_qty, ...rest } =
checkinResult.att_detail;
const attendee: Attendee = {
...rest,
total_qty,
refund_status: rest.refund_status ?? null,
};
await insertAttendee(
db,
attendee,
checkinResult.events
);
}
eventBus.emit('ticketCheckedIn');
refetch();
router.replace({
pathname: '/(tabs)/checked-in',
params: {
data: JSON.stringify(checkinResult),
// Below parameters used to redirect the user back on the page form where they came from
datetimeId: params.datetime_id,
dateId: params.date_id,
eventLabel: params.event_label,
},
});
}
} else {
if (!existingTicket) {
throw new Error('Ticket not found locally.');
}
let localDbResponse = null;
const eventId = eventData.events.event_id;
const basePayload = {
eventId: eventId,
orderId,
datetimeId,
sync: 0,
};
if (existingTicket.status === AttendeeStatus.CheckedIn) {
const payload = {
...basePayload,
checkedInDate: checkedInDateFormat(),
chk_status: TicketStatus.CHECKED,
};
localDbResponse = await updateCancelledAttendeeTicketStatus(
db,
payload
);
/*
* Note: In case of refunded and canceled users, no need to increment the order checked
* */
// Increment checked
await incrementCheckedCount(db, eventId, datetimeId);
} else if (existingTicket.status === AttendeeStatus.Refunded) {
/* Refund case */
const refundMessage = CHECKIN_MESSAGES.REFUND_MESSAGE;
const payload = {
...basePayload,
checkedInDate: null,
refunded_on: existingTicket?.refunded_on,
canceled_on: null,
chk_status: TicketStatus.UNCHECKED,
message: refundMessage,
};
localDbResponse = await updateCancelledAttendeeTicketStatus(
db,
payload
);
} else if (existingTicket.status === AttendeeStatus.Canceled) {
/*
* canceled
* */
const cancelledMessage = CHECKIN_MESSAGES.CANCELLED_MESSAGE;
const payload = {
...basePayload,
checkedInDate: null,
refunded_on: null,
canceled_on: existingTicket?.canceled_on,
chk_status: TicketStatus.UNCHECKED,
message: cancelledMessage,
};
localDbResponse = await updateCancelledAttendeeTicketStatus(
db,
payload
);
}
/*
* checked Date
* if there is checked_date and it status chk_status not already "1"
* */
eventBus.emit('ticketCheckedIn');
refetch();
localRefetch();
router.replace({
pathname: '/(tabs)/checked-in',
params: {
data: JSON.stringify(localDbResponse),
// Below parameters used to redirect the user back on the page form where they came from
datetimeId: params.datetime_id,
dateId: params.date_id,
eventLabel: params.event_label,
},
});
}
} catch (error: any) {
console.log(error.message);
const DELETE_MESSAGE = EVENT_ERROR_MESSAGES.DELETE_MESSAGE;
const REJECTED_MESSAGE = EVENT_ERROR_MESSAGES.REJECTED_MESSAGE;
const EXPIRED_MESSAGE = EVENT_ERROR_MESSAGES.EXPIRED_MESSAGE;
if (error?.message?.includes(DELETE_MESSAGE)) {
await cleanLocalDB(
db,
eventLabel as string,
datetimeId as string
);
await queryClient.invalidateQueries({ queryKey: ['evList'] });
await queryClient.invalidateQueries({
queryKey: ['eventListProfile'],
});
alert(ERROR_MESSAGE_OVERRIDE.EVENT_MESSAGE);
router.replace('/');
} else if (error?.message?.includes(REJECTED_MESSAGE)) {
await cleanLocalDB(
db,
eventLabel as string,
datetimeId as string
);
await queryClient.invalidateQueries({ queryKey: ['evList'] });
await queryClient.invalidateQueries({
queryKey: ['eventListProfile'],
});
await queryClient.invalidateQueries({ queryKey: ['eventFV'] });
alert(REJECTED_MESSAGE);
router.replace('/');
} else if (error?.message?.includes(EXPIRED_MESSAGE)) {
await cleanLocalDB(
db,
eventLabel as string,
datetimeId as string
);
await queryClient.invalidateQueries({ queryKey: ['evList'] });
await queryClient.invalidateQueries({ queryKey: ['eventFV'] });
await queryClient.invalidateQueries({
queryKey: ['eventListProfile'],
});
alert(EXPIRED_MESSAGE);
router.replace('/');
}
setErrorMessage((prev) => ({ ...prev, [orderId]: error.message }));
} finally {
setIsLoading((prev) => ({ ...prev, [orderId]: false }));
}
};
const handleTryAgain = async (orderId: string, datetimeId: string) => {
await handleManualCheckIn(orderId, datetimeId);
};
return (
item?.orderid?.toString()}
renderItem={({ item }) => (
)}
showsVerticalScrollIndicator={false}
onEndReached={loadMore}
onEndReachedThreshold={1}
initialNumToRender={10}
maxToRenderPerBatch={30}
getItemLayout={(data, index) => ({
length: ITEM_HEIGHT, // height of each item
offset: ITEM_HEIGHT * index,
index,
})}
windowSize={10}
removeClippedSubviews
ListFooterComponent={
loading ? : null
}
/>
);
}
const styles = StyleSheet.create({
list_org_wrp_lastrow: {
paddingBottom: 70,
},
list_org_wrp: {
// height: ITEM_HEIGHT,
backgroundColor: '#fff',
marginTop: 15,
padding: 11,
boxShadow: '0 7 10 rgba(0, 0, 0, 0.03)',
borderRadius: 5,
borderWidth: 1,
borderColor: 'rgba(0, 0, 0, 0.125)',
},
nme_byr: {
fontSize: 16,
fontWeight: 600,
marginBottom: 4,
},
list_orderbyr: {
fontSize: 15,
fontWeight: 400,
marginBottom: 2,
color: ' #808080',
},
list_qtybyr: {
fontSize: 15,
fontWeight: 500,
marginBottom: 2,
color: '#4ba03e',
},
btn_checkin_btn_trng: {
height: '100%',
alignItems: 'center',
justifyContent: 'center',
marginRight: 4,
},
checkinbtnmn: {
padding: 10,
borderRadius: 3,
},
chkedin_btntxtss: {
fontWeight: 600,
},
});
< /code>
import React, { useEffect } from 'react';
import {
View,
Text,
ScrollView,
StyleSheet,
ActivityIndicator,
} from 'react-native';
import { useDataProvider } from '@/provider/DataProvider';
import { FlatList } from 'react-native';
import { useSQLiteContext } from 'expo-sqlite';
import { useCheckedIn } from '@/hooks/useCheckedIn';
import EmptyList from '@/components/EmptyList';
import { useFocusEffect } from 'expo-router';
import eventBus from '@/eventBus';
import removeSecondsFromDateString from '@/utils/removeSecondsFromDateString';
const ITEM_HEIGHT = 100;
interface Attendee {
orderid: string;
fname: string;
lname: string;
total_qty: string;
chk_status: string;
checked_date: string;
}
function TicketCheckedInCard({ attendee }: { attendee: Attendee }) {
console.log("Rendered:", attendee.orderid);
return (
{attendee.fname} {attendee.lname}
OrderId #{attendee?.orderid?.slice(-6)}
Qty {attendee.total_qty}
Checked
{attendee.checked_date && (
{/*{attendee.checked_date}*/}
{removeSecondsFromDateString(attendee.checked_date)}
)}
);
}
export default function TicketCheckedInTab() {
const db = useSQLiteContext();
const {
eventData,
eventLabel,
datetimeId,
refetch,
searchQuery,
setSearchQuery,
isOnline,
} = useDataProvider();
const {
buyers,
loading,
hasMore,
loadMore,
refetch: localRefetch,
} = useCheckedIn(
db,
eventLabel as string,
datetimeId as string,
searchQuery
);
useFocusEffect(
React.useCallback(() => {
// refetch(); // reload buyers whenever tab is focused
// // if(searchQuery) {
// setSearchQuery('') // we need to set the search here everytime we switch to checked-in tab, since the search is global if we don't do this then it will reflect the last searched value in checked-in tab
// }
localRefetch();
}, [eventLabel, datetimeId])
);
useEffect(() => {
const listener = () => {
// refetch();
localRefetch();
};
eventBus.on('ticketCheckedIn', listener);
eventBus.on('reset',listener);
return () => {
eventBus.off('ticketCheckedIn', listener);
eventBus.off('reset',listener);
};
}, []);
/* state to fix overlapping issue in rendering attendee list */
// const [initialRender, setInitialRender] = React.useState(true);
/* end of overlapping state */
// const CheckedInConfirmationList = eventData?.attendees?.filter(
// (attendee: Attendee) => attendee?.chk_status.toString() === '1'
// );
return (
item?.orderid?.toString()}
renderItem={({ item }) => }
showsVerticalScrollIndicator={false}
onEndReached={loadMore}
onEndReachedThreshold={1}
initialNumToRender={10}
// initialNumToRender={buyers.length}
getItemLayout={(data, index) => ({
length: ITEM_HEIGHT, // height of each item
offset: ITEM_HEIGHT * index,
index,
})}
maxToRenderPerBatch={30}
windowSize={10}
removeClippedSubviews={false}
ListFooterComponent={
loading ? : null
}
/>
//
// {CheckedInConfirmationList?.map((item) => (
//
// ))}
//
// {/* Intentionally left paddingBottom so that QRcode scanner will not overlay on event list */}
//
//
//
);
}
const styles = StyleSheet.create({
list_org_wrp_lastrow: {
paddingBottom: 70,
},
list_org_wrp: {
backgroundColor: '#fff',
marginTop: 15,
padding: 11,
boxShadow: '0 7 10 rgba(0, 0, 0, 0.03)',
borderRadius: 5,
borderWidth: 1,
borderColor: 'rgba(0, 0, 0, 0.125)',
},
nme_byr: {
fontSize: 16,
fontWeight: 600,
marginBottom: 4,
},
list_orderbyr: {
fontSize: 15,
fontWeight: 400,
marginBottom: 2,
color: ' #808080',
},
list_qtybyr: {
fontSize: 15,
fontWeight: 500,
marginBottom: 2,
color: '#4ba03e',
},
});
Подробнее здесь: https://stackoverflow.com/questions/797 ... nd-android
Реагируйте нативные отставания во время прокрутки на iOS и Android ⇐ IOS
-
- Похожие темы
- Ответы
- Просмотры
- Последнее сообщение
-
-
Нативные модули: реагируйте нативные носитые модульные подача камеры не видно
Anonymous » » в форуме Android - 0 Ответы
- 10 Просмотры
-
Последнее сообщение Anonymous
-
-
-
Как я могу предотвратить фоновое присоединение: исправлено; от отставания моего сайта?
Anonymous » » в форуме CSS - 0 Ответы
- 18 Просмотры
-
Последнее сообщение Anonymous
-