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) {
|
Widget _body(BuildContext context) {
|
||||||
final pages = <Widget>[
|
final builders = <WidgetBuilder>[
|
||||||
_recommend(context),
|
_recommend,
|
||||||
_recommendDiscover(context),
|
_recommendDiscover,
|
||||||
FollowingPage(
|
(context) => FollowingPage(
|
||||||
onGoHome: () => logic.select(0),
|
onGoHome: () => logic.select(0),
|
||||||
favoriteController: context.read<FavoriteController>(),
|
favoriteController: context.read<FavoriteController>(),
|
||||||
historyRequest: logic.followingHistoryRequest,
|
historyRequest: logic.followingHistoryRequest,
|
||||||
visible: logic.tab == 2,
|
visible: logic.tab == 2,
|
||||||
),
|
),
|
||||||
_my(context),
|
_my,
|
||||||
];
|
];
|
||||||
return IndexedStack(
|
return _LazyTabStack(index: logic.tab, builders: builders);
|
||||||
index: logic.tab,
|
|
||||||
children: [
|
|
||||||
for (var index = 0; index < pages.length; index++)
|
|
||||||
TickerMode(enabled: logic.tab == index, child: pages[index]),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _recommend(BuildContext context) {
|
Widget _recommend(BuildContext context) {
|
||||||
@@ -248,3 +242,42 @@ class _HomeTabsState extends State<_HomeTabs> {
|
|||||||
logic.select(tab);
|
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.pumpWidget(_app(catalog: catalog, history: history));
|
||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
// 首页默认停在推荐 tab:追剧页虽在 IndexedStack 里,也不该提前拉观看历史。
|
// 首页默认停在推荐 tab:追剧页在启动时还没被构建,不该提前拉观看历史。
|
||||||
// 启动时只有「我的」页会拉一次,追剧页若也拉就会变成 2。
|
expect(history.recentCalls, 0);
|
||||||
expect(history.recentCalls, 1);
|
|
||||||
|
|
||||||
await tester.tap(find.byKey(const Key('tab-follow')));
|
await tester.tap(find.byKey(const Key('tab-follow')));
|
||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
|
|||||||
Reference in new issue
Block a user