后台导航器重建
Offstage Navigators rebuild
我已经为 bottomNavigationBar
实现了多个 Offstage
Navigators
,可以查看更多详细信息 here。问题是,当使用这种方法时,每次我们 select 一个底部导航项时,FutureBuilder
运行 future 方法并重建整个小部件,每个 Offstage
小部件及其所有 children也重建了。
对于每个 Offstage
小部件,我通过 html 请求加载数据,这意味着每次切换选项卡时,都会发出 5 个请求。
这是我的主 Scaffold
,其中包含 bottomNavigationBar
。
@override
Widget build(BuildContext context) {
TabProvider tabProvider = Provider.of<TabProvider>(context);
return FutureBuilder(
future: initProvider(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return WillPopScope(
onWillPop: _onWillPop,
child: Scaffold(
appBar: AppBar(
title: Text(tabName[tabProvider.currentTab],
),
body: Stack(children: <Widget>[
_buildOffstageNavigator(TabItem.feed, tabProvider.currentTab),
_buildOffstageNavigator(TabItem.explore, tabProvider.currentTab),
_buildOffstageNavigator(TabItem.guide, tabProvider.currentTab),
_buildOffstageNavigator(TabItem.map, tabProvider.currentTab),
_buildOffstageNavigator(TabItem.profile, tabProvider.currentTab),
]),
bottomNavigationBar: BottomNavigation(
currentTab: tabProvider.currentTab,
onSelectTab: tabProvider.selectTab,
),
),
);
} else {
return Text('Loading');
}
},
);
}
FutureBuilder
将初始化我的提供程序中的值,以便每个选项卡都可以访问缓存的数据。
下面的_buildOffstageNavigator
会return
return Offstage(
offstage: currentTab != tabItem,
child: TabNavigator(
navigatorKey: navigatorKeys[tabItem],
tabItem: tabItem,
),
);
下面是构建在 Scaffold
主体内部的小部件,因此在上面的 Offstage
Navigator
内部。
@override
Widget build(BuildContext context) {
TabProvider tabProvider = Provider.of<TabProvider>(context);
States stateData = tabProvider.exploreStateCache;
return Container(
child: ListView(
children: <Widget>[
Text(stateData.stateName),
Text(stateData.stateDescription),
],
),
);
}
我已遵循此 与提供商一起使用期货的建议,但还缺少其他内容
与其在构建方法中创建未来,正如您所注意到的,可能会调用多次,不如在仅调用一次的地方创建它们。比如一个StatefulWidget的initState:
class Foo extends StatefulWidget {
@override
_FooState createState() => _FooState();
}
class _FooState extends State<Foo> {
Future<MyData> _dataFuture;
@override
void initState() {
super.initState();
_dataFuture = getData();
}
@override
Widget build(BuildContext context) => FutureBuilder<MyData>(
future: _dataFuture,
builder: (context, snapshot) => ...,
);
}
您可以改进的第二件事是当提供商为 TabProvider
提供新值时减少重建内容的范围。当 Data
有新值时,您调用 Provider.of<Data>(context)
的上下文会重建。使用 provider 包提供的各种其他小部件可以最方便地完成此操作,例如 Consumer
和 Selector
.
因此删除 Provider<TabProvder>.of(context)
调用并使用 Consumer
s 和 Selector
s。例如,仅在切换选项卡时重建标题:
AppBar(
title: Selector<TabProvider, String>(
selector: (context, tabProvider) => tabName[tabProvider.currentTab],
builder: (context, title) => Text(title),
),
)
Selector 仅在其 selector
回调的结果与先前值不同时重建 Text(title)
小部件。 _buildOffstageNavigator
类似:
Widget _buildOffstageNavigator(BuildContext context, TabItem tabItem) {
return Selector<TabProvider, bool>(
selector: (context, tabProvider) => tabProvider.currentTab != tabItem,
builder: (context, isCurrent) => Offstage(
offstage: isCurrent,
child: Selector<TabProvider, Key>(
selector: (context, tabProvider) => tabProvider.navigatorKeys[tabItem],
builder: (context, tabKey) => TabNavigator(
navigatorKey: tabKey,
tabItem: tabItem,
),
),
);
}
(注意:所有代码未经测试且包含拼写错误)
我已经为 bottomNavigationBar
实现了多个 Offstage
Navigators
,可以查看更多详细信息 here。问题是,当使用这种方法时,每次我们 select 一个底部导航项时,FutureBuilder
运行 future 方法并重建整个小部件,每个 Offstage
小部件及其所有 children也重建了。
对于每个 Offstage
小部件,我通过 html 请求加载数据,这意味着每次切换选项卡时,都会发出 5 个请求。
这是我的主 Scaffold
,其中包含 bottomNavigationBar
。
@override
Widget build(BuildContext context) {
TabProvider tabProvider = Provider.of<TabProvider>(context);
return FutureBuilder(
future: initProvider(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return WillPopScope(
onWillPop: _onWillPop,
child: Scaffold(
appBar: AppBar(
title: Text(tabName[tabProvider.currentTab],
),
body: Stack(children: <Widget>[
_buildOffstageNavigator(TabItem.feed, tabProvider.currentTab),
_buildOffstageNavigator(TabItem.explore, tabProvider.currentTab),
_buildOffstageNavigator(TabItem.guide, tabProvider.currentTab),
_buildOffstageNavigator(TabItem.map, tabProvider.currentTab),
_buildOffstageNavigator(TabItem.profile, tabProvider.currentTab),
]),
bottomNavigationBar: BottomNavigation(
currentTab: tabProvider.currentTab,
onSelectTab: tabProvider.selectTab,
),
),
);
} else {
return Text('Loading');
}
},
);
}
FutureBuilder
将初始化我的提供程序中的值,以便每个选项卡都可以访问缓存的数据。
下面的_buildOffstageNavigator
会return
return Offstage(
offstage: currentTab != tabItem,
child: TabNavigator(
navigatorKey: navigatorKeys[tabItem],
tabItem: tabItem,
),
);
下面是构建在 Scaffold
主体内部的小部件,因此在上面的 Offstage
Navigator
内部。
@override
Widget build(BuildContext context) {
TabProvider tabProvider = Provider.of<TabProvider>(context);
States stateData = tabProvider.exploreStateCache;
return Container(
child: ListView(
children: <Widget>[
Text(stateData.stateName),
Text(stateData.stateDescription),
],
),
);
}
我已遵循此
与其在构建方法中创建未来,正如您所注意到的,可能会调用多次,不如在仅调用一次的地方创建它们。比如一个StatefulWidget的initState:
class Foo extends StatefulWidget {
@override
_FooState createState() => _FooState();
}
class _FooState extends State<Foo> {
Future<MyData> _dataFuture;
@override
void initState() {
super.initState();
_dataFuture = getData();
}
@override
Widget build(BuildContext context) => FutureBuilder<MyData>(
future: _dataFuture,
builder: (context, snapshot) => ...,
);
}
您可以改进的第二件事是当提供商为 TabProvider
提供新值时减少重建内容的范围。当 Data
有新值时,您调用 Provider.of<Data>(context)
的上下文会重建。使用 provider 包提供的各种其他小部件可以最方便地完成此操作,例如 Consumer
和 Selector
.
因此删除 Provider<TabProvder>.of(context)
调用并使用 Consumer
s 和 Selector
s。例如,仅在切换选项卡时重建标题:
AppBar(
title: Selector<TabProvider, String>(
selector: (context, tabProvider) => tabName[tabProvider.currentTab],
builder: (context, title) => Text(title),
),
)
Selector 仅在其 selector
回调的结果与先前值不同时重建 Text(title)
小部件。 _buildOffstageNavigator
类似:
Widget _buildOffstageNavigator(BuildContext context, TabItem tabItem) {
return Selector<TabProvider, bool>(
selector: (context, tabProvider) => tabProvider.currentTab != tabItem,
builder: (context, isCurrent) => Offstage(
offstage: isCurrent,
child: Selector<TabProvider, Key>(
selector: (context, tabProvider) => tabProvider.navigatorKeys[tabItem],
builder: (context, tabKey) => TabNavigator(
navigatorKey: tabKey,
tabItem: tabItem,
),
),
);
}
(注意:所有代码未经测试且包含拼写错误)