如何在 Flutter 中获取有关提供者上下文更改的网络数据
Posted
技术标签:
【中文标题】如何在 Flutter 中获取有关提供者上下文更改的网络数据【英文标题】:How to fetch network data on provider context change in Flutter 【发布时间】:2021-05-31 20:57:48 【问题描述】:我有一个带有一些奇怪功能的 Flutter 应用程序,但它是必需的。该应用程序的 BottomNavigationBar 页面包含在 IndexedStack 中,因此如果您转到此 IndexedStack 的其他页面,页面不会重新加载并保持持久性。
class _MyHomePageState extends State<MyHomePage>
//...
@override
Widget build(BuildContext context)
return Scaffold(
body: IndexedStack(
index: selectedIndex,
children: bottomBarPages(),
),
bottomNavigationBar: BottomNavigationBar(
items: navItems,
currentIndex: selectedIndex,
onTap: _onNavItemTapped,
),
);
其中一个页面是 ProfilePage,您可以在其中选择用户列表。我使用如下所示的 ChangeNotifier:
class MainUserInfo extends ChangeNotifier
List<UserInfo> _users;
UserInfo _chosenUser;
//... some get/set/etc methods here
另一个底部导航栏页面 TheOtherPage 取决于所选用户 (_chosenUser),在 initState 上它从网络加载数据:
class TheOtherPage extends StatefulWidget
//...
bool isLoading = true;
@override
void initState()
super.initState();
getAccountData();
void getAccountData() async
//some fetch happening here
setState(()
model = response.data;
isLoading = false;
);
问题是字段 _chosenUser 更改后,我需要 TheOtherPage 从网络加载所选用户的数据。但我不知道如何处理它。如果我使用 context.read 或 context.select 它肯定会跟踪更改的 _chosenUser,但不会获取新选择的数据:
var mainUserInfo = context.read<MainUserInfo>();
//or
var chosenUser = context.select<MainUserInfo, UserInfo>((userInfo) => userInfo.chosenUser);
而且我不想将 TheOtherPage 所需的数据保存在 UserInfo 对象中,因为数据太多,并且在 MainUserInfo._users 中为每个用户加载如此多的数据不是一个选项。 我还可以跟踪加载状态,因为使用“bool Isloading”我可以在获取所需数据时显示一些精美的占位符。
所以一般问题是如何使 TheOtherPage 获取有关 ProfilePage 上 ChangeNotifier 更改字段的数据。也许我的整个方法很糟糕,我不需要在这里使用 Provider 和 ChangeNotifier,我想看看任何建议。谢谢
【问题讨论】:
【参考方案1】:这是 provider 试图解决的一个典型案例:在 2 个小部件之间共享数据
这是你的树结构:
Scaffold
\ IndexedStack
\ ProfilePage <- share MainUserInfo
\ TheOtherPage <- share MainUserInfo
问题是您希望 TheOtherPage 收听 MainUserInfo
而它没有。 (因为 statefulwidget 中的initState()
只会被调用一次,即使状态改变了)
我建议你可以听build
方法里面的provider,用FutureBuilder处理加载状态:
class _TheOtherPageState extends State<TheOtherPage>
//...
@override
void initState()
super.initState();
// do nothing here
@override
Widget build(BuildContext context)
// rebuild everytime the MainUserInfo get notified by watching it
// final mainUserInfo = context.watch<MainUserInfo>();
// rebuild everytime the chosenUser change inside MainUserInfo
final chosenUser = context.select<MainUserInfo, UserInfo>((userInfo) => userInfo.chosenUser);
return FutureBuilder(
future: getAccountData(chosenUser).
builder: (BuildContext context, AsyncSnapshot snapshot)
if(snapshot.connectionState == ConnectionState.done && snapshot.hasData)
model = snapshot.data;
// return a page with the model
else
// return the loading placeholders
);
Future getAccountData(user) async
//some fetch happening here with the user
// ...
return response.data;
您还可以尝试一件事:使用 const
关键字
(How to deal with unwanted widget build?)
...
body: IndexedStack(
index: selectedIndex,
children: [
ProfilePage(),
const TheOtherPage(), // here
],
),
...
class TheOtherPage extends StatefulWidget
const TheOtherPage(Key key) : super(key: key); // and here
@override
_TheOtherPageState createState() => _TheOtherPageState();
【讨论】:
感谢您的回答。这种方法存在一个问题,即 TheOtherPage 不再是持久的 IndexedStack:每次我点击相应的 BottomBar 按钮时,TheOtherPage 都会再次获取数据 您的 BottomBar 按钮是否更改了MainUserInfo
内的任何值?如果您只想监听MainUserInfo
内部的特定值变化,可以改用context.select
。
TheOtherPage 是否只显示chosenUser
的信息?我更新了答案。
我已经将context.select
用于chosenUser
。问题不在于提供者方法,我相信FutureBuilder
会以某种方式破坏IndexedStack
。我只需按下BottomNavigationBar
和TheOtherPage
的按钮即可重建并获取数据
谢谢!这可以节省一天的时间。我以前没用过const
,所以其实我很糟糕,现在应该更频繁地使用const
以上是关于如何在 Flutter 中获取有关提供者上下文更改的网络数据的主要内容,如果未能解决你的问题,请参考以下文章
如何获取 AlertDialog 的宽高 - Flutter Web
Flutter:如何在 Flutter 中使用 Switch 更改主题 - 我已经使用 Provider 实现了这个明暗主题,但不能使用 switch 更改