调用notifylisters时Flutter Widget不更新



我有一个ChangeNotifier从Firebase Firestore正确获取数据。然而,我的StatefulWidget在加载此数据时不更新。我哪里做错了?

class MyViewModel with ChangeNotifier {
MyViewModel();
MyModel _myModel;
FirebaseRepository _firebaseRepository = FirebaseRepository();
void loadData(String userId) async {
_myModel =
await _firebaseRepository.getData(userId);
notifyListeners();
}
getModelName(){
return _myModel.name;
}
}

ChangeNotifierProvider设置在我的小部件树的顶层

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(
create: (context) => MyViewModel(),
),
],
child: MaterialApp(
home: HomeWithBottomNav(title: 'Bottom Nav Home Page'),
routes: <String, WidgetBuilder>{
// define the routes

MyPage.routeName: (BuildContext context) => MyPage(),

}));
}
}

和一个试图监听数据

StatefulWidget
class MyPage extends StatefulWidget {
static const String routeName = "/myPage";
@override
_State createState() => _State();
}
class _State extends State<MyPage> {
MyViewModel myViewModel =
new MyViewModel();
@override
void initState() {
myViewModel.loadData('userId');
super.initState();
}
@override
Widget build(BuildContext context) {
Provider.of<MyViewModel>(context);
return Consumer<MyViewModel>(
builder: (context, myViewModel, child) {
AppBar appBar = AppBar(
title: Text("Model Name: $myViewModel.getModelName()"), // This is not getting the data fetched from firestore
);
SingleChildScrollView singleChildScrollView = SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[],
),
);
Scaffold scaffold =
Scaffold(appBar: appBar, body: singleChildScrollView);
return scaffold;
},
);
}
}

你应该这样调用myViewModel:

Provider.of<myViewModel>(context,listen:false).loadData('userId');

但是默认情况下你不能在initstate中调用它因为我们没有上下文

我认为这是因为你有两个MyViewModel实例。一个是在这里创建的:

ChangeNotifierProvider(
create: (context) => MyViewModel(),
),

和这里的另一个

class _State extends State<MyPage> {
MyViewModel myViewModel =
new MyViewModel();

你调用loadData函数的那个是第二个,但是你从消费者那里获得访问权限的那个是第一个。我建议您将有状态小部件更改为无状态小部件,删除第二次实例化MyViewModel时,而不是从initsatate调用所需的函数,而是从MyViewModel的构造函数调用它。我希望这对你有帮助。

我认为问题是两个实例,一个提供状态变化,这是你的视图被注册为侦听器的那个,不是你调用loadData的那个。

这个应该可以工作:

@override
void initState() {
WidgetsBinding.instance.addPostFrameCallback((_) async { 
await Provider.of<MyViewModel>(context, listen: false).loadData('userId');
});
super.initState();
} 

您不能在initState方法中直接调用异步方法,但是您可以注册一个async回调,以便在Page小部件挂载后执行,因此可以使用addPostFrameCallback。因为它是异步的你也可以访问BuildContext

最新更新