perf(home): 四个根 tab 改为首次可见才构建
原先 IndexedStack 冷启动就把推荐/发现/追剧/我的四棵子树全建出来,各自还会发请求; 现在只建当前 tab,切过去再建并常驻,冷启动少三页构建和一次观看历史请求。
This commit is contained in:
1 parent
9f7301305e
commit
5649e4c3d4
2 files changed
+47
-15
No files matched your search
@@ -161,24 +161,18 @@ class _HomeTabsState extends State<_HomeTabs> {
|
||||
}
|
||||
|
||||
Widget _body(BuildContext context) {
|
||||
final pages = <Widget>[
|
||||
_recommend(context),
|
||||
_recommendDiscover(context),
|
||||
FollowingPage(
|
||||
final builders = <WidgetBuilder>[
|
||||
_recommend,
|
||||
_recommendDiscover,
|
||||
(context) => FollowingPage(
|
||||
onGoHome: () => logic.select(0),
|
||||
favoriteController: context.read<FavoriteController>(),
|
||||
historyRequest: logic.followingHistoryRequest,
|
||||
visible: logic.tab == 2,
|
||||
),
|
||||
_my(context),
|
||||
_my,
|
||||
];
|
||||
return IndexedStack(
|
||||
index: logic.tab,
|
||||
children: [
|
||||
for (var index = 0; index < pages.length; index++)
|
||||
TickerMode(enabled: logic.tab == index, child: pages[index]),
|
||||
],
|
||||
);
|
||||
return _LazyTabStack(index: logic.tab, builders: builders);
|
||||
}
|
||||
|
||||
Widget _recommend(BuildContext context) {
|
||||
@@ -248,3 +242,42 @@ class _HomeTabsState extends State<_HomeTabs> {
|
||||
logic.select(tab);
|
||||
}
|
||||
}
|
||||
|
||||
/// 四个根 tab 的容器:只有被访问过的 tab 才真正构建并常驻。
|
||||
///
|
||||
/// 冷启动时只建推荐页,其余 tab 等第一次切过去再建,省掉三棵子树和它们各自的请求。
|
||||
class _LazyTabStack extends StatefulWidget {
|
||||
const _LazyTabStack({required this.index, required this.builders});
|
||||
|
||||
final int index;
|
||||
final List<WidgetBuilder> builders;
|
||||
|
||||
@override
|
||||
State<_LazyTabStack> createState() => _LazyTabStackState();
|
||||
}
|
||||
|
||||
class _LazyTabStackState extends State<_LazyTabStack> {
|
||||
late final Set<int> _visited = {widget.index};
|
||||
|
||||
@override
|
||||
void didUpdateWidget(covariant _LazyTabStack oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
_visited.add(widget.index);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return IndexedStack(
|
||||
index: widget.index,
|
||||
children: [
|
||||
for (var index = 0; index < widget.builders.length; index++)
|
||||
TickerMode(
|
||||
enabled: widget.index == index,
|
||||
child: _visited.contains(index)
|
||||
? widget.builders[index](context)
|
||||
: const SizedBox.shrink(),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -36,9 +36,8 @@ void main() {
|
||||
await tester.pumpWidget(_app(catalog: catalog, history: history));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// 首页默认停在推荐 tab:追剧页虽在 IndexedStack 里,也不该提前拉观看历史。
|
||||
// 启动时只有「我的」页会拉一次,追剧页若也拉就会变成 2。
|
||||
expect(history.recentCalls, 1);
|
||||
// 首页默认停在推荐 tab:追剧页在启动时还没被构建,不该提前拉观看历史。
|
||||
expect(history.recentCalls, 0);
|
||||
|
||||
await tester.tap(find.byKey(const Key('tab-follow')));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
Reference in new issue
Block a user