使用提供者获取数据 onLoad
Posted
技术标签:
【中文标题】使用提供者获取数据 onLoad【英文标题】:Using provider in fetching data onLoad 【发布时间】:2019-12-16 16:04:10 【问题描述】:我来自 android 开发,对 Flutter 开发非常陌生,我遇到过用于状态管理的 ScopedModel 和 Provider,我为我的用例选择了 Provider。我的用例是登录后,仪表板应该用数据呈现。我创建了一个扩展 ChangeNotifier 的 ViewModel,并希望使用它以便我可以在不同的小部件中重用这些数据。我不完全确定如何使用我的 ViewModel 加载小部件的数据。一些人可以帮助我正确的设计模式。
abstract class ViewModel extends ChangeNotifier
class EventViewModel extends ViewModel
EventDataState _eventDataState = EventDataUnInitialized();
EventDataState get eventDataState => _eventDataState;
set eventDataState(EventDataState value)
_eventDataState = value;
notifyListeners();
gatherEvents()
eventDataState = EventDataLoading();
EventService.create().getEvents().then((data)
var responseData = json.decode(data.bodyString);
eventDataState = EventDataLoaded(
responseData.map((each) => new EventData.fromJson(each)).toList());
).catchError((err)
eventDataState = EventDataLoadFailed("Failed to do something");
);
class DashboardPage extends StatefulWidget
static const routename = "/dashboard";
@override
_DashboardPageState createState() => _DashboardPageState();
class _DashboardPageState extends State<DashboardPage>
@override
Widget build(BuildContext context)
return Consumer<EventViewModel>(
builder: (context, vm, child)
if (vm.eventDataState is EventDataUnInitialized)
vm.gatherEvents();
return Scaffold(body: Container(),);
else if (vm.eventDataState is EventDataLoading)
return Scaffold(body: Container(child: Center(child: CircularProgressIndicator(),),),);
else if (vm.eventDataState is EventDataLoadFailed)
return Scaffold(body: Container(child: Center(child: Text("Error Loading Data."),),),);
else
return Scaffold(body: Container(child: Center(child: Text("Data done loading..."),),),);
,
);
我得到的错误是:
I/flutter (30492): ══╡ EXCEPTION CAUGHT BY FOUNDATION LIBRARY ╞════════════════════════════════════════════════════════
I/flutter (30492): The following assertion was thrown while dispatching notifications for EventViewModel:
I/flutter (30492): setState() or markNeedsBuild() called during build.
I/flutter (30492): This ListenableProvider<EventViewModel> widget cannot be marked as needing to build because the
I/flutter (30492): framework is already in the process of building widgets. A widget can be marked as needing to be
I/flutter (30492): built during the build phase only if one of its ancestors is currently building. This exception is
I/flutter (30492): allowed because the framework builds parent widgets before children, which means a dirty descendant
I/flutter (30492): will always be built. Otherwise, the framework might not visit this widget during this build phase.
I/flutter (30492): The widget on which setState() or markNeedsBuild() was called was:
I/flutter (30492): ListenableProvider<EventViewModel>
I/flutter (30492): The widget which was currently being built when the offending call was made was:
I/flutter (30492): Consumer<EventViewModel>
【问题讨论】:
或者请帮我一个合适的小部件,我应该在视图中使用 我怀疑删除 vm.gatherEvents() 至少可以消除错误。 【参考方案1】:您可以使用 SchedulerBinding 来防止此异常:
备选方案 1:
initState()
super.initState();
final gatherEvents =
Provider.of<EventViewModel>(context, listen: false).gatherEvents;
SchedulerBinding.instance.addPostFrameCallback((_) => gatherEvents());
备选方案 2:
initState()
super.initState();
Future.microtask(() =>
Provider.of<EventViewModel>(context, listen: false).gatherEvents();
);
【讨论】:
我节省了很多时间。我一直在寻找同样的东西。【参考方案2】:我正在使用get_it,它提供了一个服务定位器,以便您在注册后可以在任何地方访问您的视图模型。
并尝试FutureBuilder
使用 API 构建小部件。
我不确定错误是否会得到解决,也许你应该在gatherEvents()方法中返回你的响应数据。
和代码:
/// * serviceLocator.dart
import 'package:get_it/get_it.dart';
GetIt serviceLocator = GetIt.instance;
void setupInfoServiceLocator()
serviceLocator.registerLazySingleton(() => EventViewModel());
/// * main.dart or somewhere else
@override
void initState()
setupInfoServiceLocator();
class _DashboardPageState extends State<DashboardPage>
final EventViewModel _viewModel = serviceLocator<EventViewModel>();
Future<EventDataState> _gatherEvents;
@override
void initState()
super.initState();
_gatherEvents = _viewModel.gatherEvents();
@override
Widget build(BuildContext context)
return FutureBuilder(
future: _gatherEvents,
builder: (BuildContext context, AsyncSnapshot snapshot)
switch (snapshot.connectionState)
case ConnectionState.none:
case ConnectionState.active:
case ConnectionState.waiting:
return Center(
child: CircularProgressIndicator();
);
case ConnectionState.done:
if (snapshot.hasError)
return Text('Error Loading Data.');
/// * there is at least three ways to access your data
final EventDataState data = _viewModel.eventDataState;
/// * or final EventDataState data = snapshot.data; if you return the response data
/// * or use Consumer<EventViewModel>(builder: (context, vm, child) => vm.eventDataState);
/// * use your data
return Text('Data done loading...');
default:
return Container();
,
);
【讨论】:
【参考方案3】:您可以在initState
生命周期中使用,见下例:
initState()
super.initState();
Provider.of<EventViewModel>(context, listen: false).gatherEvents;
【讨论】:
这不起作用,不幸的是,我得到了以下断言在构建 Builder 时被抛出:dependOnInheritedWidgetOfExactType以上是关于使用提供者获取数据 onLoad的主要内容,如果未能解决你的问题,请参考以下文章
wepy父组件onload中请求数据,更新.sync动态传值绑定的数据,子组件onload中获取不到值。