1import React, {memo, useCallback, useEffect, useState} from 'react'; 2import {useAtomValue} from 'jotai'; 3import {ISearchResult, queryAtom} from '../../store/atoms'; 4import {renderMap} from './results'; 5import useSearch from '../../hooks/useSearch'; 6import Loading from '@/components/base/loading'; 7import {RequestStateCode} from '@/constants/commonConst'; 8import ListLoading from '@/components/base/listLoading'; 9import Empty from '@/components/base/empty'; 10import ListReachEnd from '@/components/base/listReachEnd'; 11import useOrientation from '@/hooks/useOrientation'; 12import {FlashList} from '@shopify/flash-list'; 13import rpx from '@/utils/rpx'; 14import {StyleSheet, View} from 'react-native'; 15 16interface IResultWrapperProps< 17 T extends ICommon.SupportMediaType = ICommon.SupportMediaType, 18> { 19 tab: T; 20 pluginHash: string; 21 pluginName: string; 22 searchResult: ISearchResult<T>; 23 pluginSearchResultRef: React.MutableRefObject<ISearchResult<T>>; 24} 25function ResultWrapper(props: IResultWrapperProps) { 26 const {tab, pluginHash, searchResult, pluginSearchResultRef} = props; 27 const search = useSearch(); 28 const [searchState, setSearchState] = useState<RequestStateCode>( 29 searchResult?.state ?? RequestStateCode.IDLE, 30 ); 31 const orientation = useOrientation(); 32 const query = useAtomValue(queryAtom); 33 34 const ResultComponent = renderMap[tab]!; 35 const data: any = searchResult?.data ?? []; 36 37 const keyExtractor = useCallback( 38 (item: any, i: number) => `${i}-${item.platform}-${item.id}`, 39 [], 40 ); 41 42 useEffect(() => { 43 if (searchState === RequestStateCode.IDLE) { 44 search(query, 1, tab, pluginHash); 45 } 46 }, []); 47 48 useEffect(() => { 49 setSearchState(searchResult?.state ?? RequestStateCode.IDLE); 50 }, [searchResult]); 51 52 const renderItem = ({item, index}: any) => ( 53 <ResultComponent 54 item={item} 55 index={index} 56 pluginHash={pluginHash} 57 pluginSearchResultRef={pluginSearchResultRef} 58 /> 59 ); 60 61 return searchState === RequestStateCode.PENDING_FIRST_PAGE ? ( 62 <Loading /> 63 ) : ( 64 <FlashList 65 extraData={searchState} 66 ListEmptyComponent={() => 67 searchState & RequestStateCode.LOADING ? null : <Empty /> 68 } 69 ListFooterComponent={() => ( 70 <View style={style.wrapper}> 71 {searchState === RequestStateCode.PENDING_REST_PAGE ? ( 72 <ListLoading /> 73 ) : searchState === RequestStateCode.FINISHED ? ( 74 <ListReachEnd /> 75 ) : ( 76 <></> 77 )} 78 </View> 79 )} 80 data={data} 81 refreshing={false} 82 onRefresh={() => { 83 search(query, 1, tab, pluginHash); 84 }} 85 onEndReached={() => { 86 (searchState === RequestStateCode.PARTLY_DONE || 87 searchState === RequestStateCode.IDLE) && 88 search(undefined, undefined, tab, pluginHash); 89 }} 90 estimatedItemSize={tab === 'sheet' ? rpx(306) : rpx(120)} 91 numColumns={ 92 tab === 'sheet' ? (orientation === 'vertical' ? 3 : 4) : 1 93 } 94 renderItem={renderItem} 95 keyExtractor={keyExtractor} 96 /> 97 ); 98} 99 100export default memo(ResultWrapper); 101const style = StyleSheet.create({ 102 wrapper: { 103 width: '100%', 104 height: rpx(140), 105 justifyContent: 'center', 106 alignItems: 'center', 107 }, 108}); 109