feat: optimize home screen data loading with pagination and refresh functionality
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import React, { memo } from 'react'
|
||||
import React, { memo, useCallback, useMemo } from 'react'
|
||||
import { Pressable, StyleSheet, Text, View, ViewStyle } from 'react-native'
|
||||
import { Image } from 'expo-image'
|
||||
import { LinearGradient } from 'expo-linear-gradient'
|
||||
@@ -41,6 +41,11 @@ export function getImageUri(
|
||||
return webpPreviewUrl || previewUrl || coverImageUrl
|
||||
}
|
||||
|
||||
// 渐变颜色常量,避免每次渲染创建新数组
|
||||
const GRADIENT_COLORS = ['rgba(17, 17, 17, 0)', 'rgba(17, 17, 17, 0.9)'] as const
|
||||
const GRADIENT_START = { x: 0, y: 0 }
|
||||
const GRADIENT_END = { x: 0, y: 1 }
|
||||
|
||||
const TemplateCardComponent: React.FC<TemplateCardProps> = ({
|
||||
id,
|
||||
title,
|
||||
@@ -52,8 +57,26 @@ const TemplateCardComponent: React.FC<TemplateCardProps> = ({
|
||||
onPress,
|
||||
testID,
|
||||
}) => {
|
||||
const aspectRatio = parseAspectRatio(aspectRatioString)
|
||||
const imageUri = getImageUri(webpPreviewUrl, previewUrl, coverImageUrl)
|
||||
const aspectRatio = useMemo(() => parseAspectRatio(aspectRatioString), [aspectRatioString])
|
||||
const imageUri = useMemo(() => getImageUri(webpPreviewUrl, previewUrl, coverImageUrl), [webpPreviewUrl, previewUrl, coverImageUrl])
|
||||
|
||||
// 使用 useCallback 缓存 onPress 回调
|
||||
const handlePress = useCallback(() => {
|
||||
if (id) {
|
||||
onPress(id)
|
||||
}
|
||||
}, [id, onPress])
|
||||
|
||||
// 缓存样式计算
|
||||
const cardStyle = useMemo(() => [styles.card, { width: cardWidth }], [cardWidth])
|
||||
const containerStyle = useMemo(() =>
|
||||
[styles.cardImageContainer, aspectRatio ? { aspectRatio } : undefined].filter(Boolean) as ViewStyle[],
|
||||
[aspectRatio]
|
||||
)
|
||||
const imageStyle = useMemo(() =>
|
||||
[styles.cardImage, aspectRatio ? { aspectRatio } : undefined].filter(Boolean) as ViewStyle[],
|
||||
[aspectRatio]
|
||||
)
|
||||
|
||||
// 如果没有 id,则不渲染卡片
|
||||
if (!id) {
|
||||
@@ -62,28 +85,23 @@ const TemplateCardComponent: React.FC<TemplateCardProps> = ({
|
||||
|
||||
return (
|
||||
<Pressable
|
||||
style={[styles.card, { width: cardWidth }]}
|
||||
onPress={() => onPress(id)}
|
||||
style={cardStyle}
|
||||
onPress={handlePress}
|
||||
testID={testID}
|
||||
>
|
||||
<View
|
||||
style={[
|
||||
styles.cardImageContainer,
|
||||
aspectRatio ? { aspectRatio } : undefined,
|
||||
].filter(Boolean) as ViewStyle[]}
|
||||
>
|
||||
<View style={containerStyle}>
|
||||
<Image
|
||||
source={{ uri: imageUri }}
|
||||
style={[
|
||||
styles.cardImage,
|
||||
aspectRatio ? { aspectRatio } : undefined,
|
||||
].filter(Boolean) as ViewStyle[]}
|
||||
style={imageStyle}
|
||||
contentFit="cover"
|
||||
cachePolicy="memory-disk"
|
||||
recyclingKey={id}
|
||||
transition={200}
|
||||
/>
|
||||
<LinearGradient
|
||||
colors={['rgba(17, 17, 17, 0)', 'rgba(17, 17, 17, 0.9)']}
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 0, y: 1 }}
|
||||
colors={GRADIENT_COLORS}
|
||||
start={GRADIENT_START}
|
||||
end={GRADIENT_END}
|
||||
style={styles.cardImageGradient}
|
||||
/>
|
||||
<Text style={styles.cardTitle} numberOfLines={1}>
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import React, { useState, memo } from 'react'
|
||||
import { View, StyleSheet, LayoutChangeEvent } from 'react-native'
|
||||
import type { CategoryTemplate } from '@repo/sdk'
|
||||
import type { CategoryTemplate, TemplateDetail } from '@repo/sdk'
|
||||
import { TemplateCard } from './TemplateCard'
|
||||
|
||||
export type Template = CategoryTemplate
|
||||
// 支持 CategoryTemplate 和 TemplateDetail 两种类型
|
||||
export type Template = CategoryTemplate | TemplateDetail
|
||||
|
||||
export interface TemplateGridProps {
|
||||
templates: CategoryTemplate[]
|
||||
templates: Template[]
|
||||
onTemplatePress: (id: string) => void
|
||||
numColumns?: number
|
||||
horizontalPadding?: number
|
||||
@@ -40,7 +41,7 @@ const TemplateGridComponent: React.FC<TemplateGridProps> = ({
|
||||
const [gridWidth, setGridWidth] = useState(0)
|
||||
|
||||
// 过滤掉没有 id 的模板
|
||||
const validTemplates = templates.filter((template): template is CategoryTemplate & { id: string } =>
|
||||
const validTemplates = templates.filter((template): template is Template & { id: string } =>
|
||||
!!template.id
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user