RN for OpenHarmony AnimeHub项目实战:最受喜爱页面开发
AnimeHub项目总结:最受喜爱页面实现与核心技术回顾 本文是AnimeHub项目实战系列的最后一篇,介绍了"最受喜爱"排行榜的实现。该榜单基于MyAnimeList用户收藏数排序,反映了动漫作品的死忠粉数量。 技术实现要点 通过API获取收藏数最高的动漫列表 使用FlatList实现分页加载 爱心图标空状态设计 与热门排行、人气排行形成多维评价体系 项目核心技术回顾 Rea

案例开源地址:https://atomgit.com/nutpi/Rn_openharmony_AnimeHub
这是 AnimeHub 项目实战系列的最后一篇。我们用最受喜爱页面来收尾,同时回顾整个项目的技术要点。
什么是"最受喜爱"
MyAnimeList 有个"Favorites"功能,用户可以把特别喜欢的动漫标记为"最爱"。这和普通的"加入列表"不同,Favorites 是精选中的精选,代表用户真正热爱的作品。
最受喜爱排行榜就是按 Favorites 数量排序的榜单。能上这个榜的作品,说明有大量用户把它标记为"最爱",是真正意义上的"神作"。
三个排行榜的区别
到这里,我们已经实现了三个排行榜:
| 排行榜 | 排序依据 | 反映的是 |
|---|---|---|
| 热门排行 | 评分 | 质量、口碑 |
| 人气排行 | 用户数 | 知名度、话题性 |
| 最受喜爱 | 收藏数 | 情感认同、死忠粉数量 |
一部作品可能评分高但收藏少(叫好不叫座),也可能收藏多但评分一般(有争议但有死忠粉)。三个榜单从不同角度展示动漫的价值。
代码实现
最受喜爱页面的代码和前两个排行榜几乎一样,只是 filter 参数不同:
const res = await getTopAnime(pageNum, 'favorite');
完整代码如下:
import React, { useEffect, useState, useCallback } from 'react';
import { View, FlatList, StyleSheet } from 'react-native';
import { Colors, Spacing } from '../../theme';
import { Anime } from '../../types';
import { getTopAnime } from '../../api/jikan';
import { AnimeListItem } from '../../components/anime';
import { Header, Loading, EmptyState } from '../../components/common';
export const FavoriteAnimeScreen = ({ navigation }: any) => {
const [animeList, setAnimeList] = useState<Anime[]>([]);
const [loading, setLoading] = useState(true);
const [loadingMore, setLoadingMore] = useState(false);
const [page, setPage] = useState(1);
const [hasMore, setHasMore] = useState(true);
const loadData = async (pageNum: number, append = false) => {
try {
if (pageNum === 1) setLoading(true);
else setLoadingMore(true);
const res = await getTopAnime(pageNum, 'favorite');
const newData = res.data || [];
if (append) {
setAnimeList(prev => [...prev, ...newData]);
} else {
setAnimeList(newData);
}
setHasMore(res.pagination?.has_next_page || false);
} catch (error) {
console.error('Load error:', error);
} finally {
setLoading(false);
setLoadingMore(false);
}
};
useEffect(() => {
loadData(1);
}, []);
const handleLoadMore = useCallback(() => {
if (!loadingMore && hasMore) {
const nextPage = page + 1;
setPage(nextPage);
loadData(nextPage, true);
}
}, [loadingMore, hasMore, page]);
const renderItem = ({ item, index }: { item: Anime; index: number }) => (
<AnimeListItem
anime={item}
rank={index + 1}
onPress={() => navigation.navigate('AnimeDetail', { animeId: item.mal_id })}
/>
);
if (loading) {
return (
<View style={styles.container}>
<Header title="最受喜爱" showBack onBack={() => navigation.goBack()} />
<Loading fullScreen text="加载中..." />
</View>
);
}
return (
<View style={styles.container}>
<Header title="最受喜爱" showBack onBack={() => navigation.goBack()} />
<FlatList
data={animeList}
renderItem={renderItem}
keyExtractor={item => item.mal_id.toString()}
contentContainerStyle={styles.list}
showsVerticalScrollIndicator={false}
onEndReached={handleLoadMore}
onEndReachedThreshold={0.5}
ListFooterComponent={loadingMore ? <Loading text="加载更多..." /> : null}
ListEmptyComponent={<EmptyState icon="heart" title="暂无数据" />}
/>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: Colors.background,
},
list: {
padding: Spacing.md,
},
});
空状态用了爱心图标(heart),和"最受喜爱"的主题呼应。
回顾:30 个页面用到的技术
写完 30 篇,我们来回顾一下整个项目用到的核心技术:
React Native 基础
- 函数组件 - 所有页面都用函数组件,配合 Hooks 使用
- JSX 语法 - 用类似 HTML 的语法描述 UI
- StyleSheet - 用 JavaScript 对象定义样式
- Flexbox 布局 - 几乎所有布局都基于 Flexbox
React Hooks
- useState - 管理组件内部状态
- useEffect - 处理副作用(数据加载、订阅等)
- useCallback - 缓存函数引用,优化性能
核心组件
- View - 容器组件,类似 div
- Text - 文本组件
- Image - 图片组件
- ScrollView - 滚动容器
- FlatList - 高性能列表,支持虚拟化
- TouchableOpacity - 可点击的容器
- TextInput - 输入框
- Switch - 开关
- Alert - 原生对话框
列表相关
- FlatList 基础配置 - data、renderItem、keyExtractor
- 分页加载 - onEndReached、onEndReachedThreshold
- 网格布局 - numColumns
- 列表装饰 - ListHeaderComponent、ListFooterComponent、ListEmptyComponent
- 下拉刷新 - refreshing、onRefresh
导航
- 页面跳转 - navigation.navigate()
- 返回 - navigation.goBack()
- 参数传递 - route.params
- 嵌套导航 - Tab Navigator + Stack Navigator
状态管理
- 本地状态 - useState 管理页面内状态
- 全局状态 - Zustand 管理跨页面状态(收藏、历史)
- 持久化 - AsyncStorage 保存数据到本地
API 调用
- fetch - 发起网络请求
- async/await - 处理异步操作
- 错误处理 - try/catch/finally
- API 封装 - 统一的请求函数
样式技巧
- 主题系统 - Colors、Spacing、FontSize、BorderRadius
- 条件样式 -
[styles.base, condition && styles.active] - 动态样式 - 根据 props 或 state 计算样式
回顾:页面类型分类
30 个页面可以分为几类:
列表页面(最多)
- 首页、搜索页、新番页、排行页
- 各种分类列表、排行榜
- 收藏页、历史记录
特点:FlatList + 分页加载 + 列表项组件
详情页面
- 动漫详情、角色详情
- 剧集列表、评论页、统计页
特点:ScrollView + 多区块布局 + 条件渲染
表单/设置页面
- 设置页、关于页
特点:ScrollView + 分组 + 开关/跳转
特殊交互页面
- 随机推荐(单条数据 + 刷新)
- 放送时间表(标签切换)
- 图片页(网格 + 大图预览)
回顾:设计模式
项目中反复出现的设计模式:
分页列表模式
const [data, setData] = useState([]);
const [loading, setLoading] = useState(true);
const [loadingMore, setLoadingMore] = useState(false);
const [page, setPage] = useState(1);
const [hasMore, setHasMore] = useState(true);
几乎所有列表页面都用这个模式。
条件渲染模式
if (loading) return <Loading />;
if (error) return <Error />;
if (data.length === 0) return <Empty />;
return <Content />;
处理不同状态的标准方式。
组件复用模式
- AnimeCard - 网格布局的动漫卡片
- AnimeListItem - 列表布局的动漫项
- Header - 统一的页面头部
- Loading - 统一的加载状态
- EmptyState - 统一的空状态
封装通用组件,在多个页面复用。
项目可以继续优化的方向
虽然 30 个页面已经完成,但项目还有很多可以优化的地方:
性能优化
- 图片懒加载和缓存
- 列表项组件用 React.memo 优化
- 数据请求缓存(React Query)
用户体验
- 骨架屏代替 Loading
- 下拉刷新
- 错误重试
- 离线支持
代码质量
- TypeScript 类型完善
- 单元测试
- E2E 测试
- 代码规范检查
功能扩展
- 用户登录
- 评论功能
- 分享功能
- 多语言支持
写在最后
30 篇文章,30 个页面,覆盖了 React Native 开发的方方面面。从最基础的列表展示,到复杂的状态管理,从简单的页面跳转,到嵌套的导航结构。
希望这个系列能帮助你入门 React Native for OpenHarmony 开发。代码不是最重要的,重要的是理解背后的思路和模式。掌握了这些,你就能举一反三,开发出自己的应用。
动漫的世界很精彩,编程的世界也很精彩。愿你在两个世界都能找到乐趣。
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
更多推荐

所有评论(0)