【问题标题】:Riverpode and Hooks in flutter, how to implement the StateNotifier for async calls?Flutter中的Riverpode和Hooks,如何实现StateNotifier进行异步调用?
【发布时间】:2021-03-06 11:07:04
【问题描述】:

我是 Flutter 的新手,最近我决定研究提供程序,以便能够重用我使用 FutureBuilder as suggested in this other question 进行的一些 sqlite DB 调用。

阅读后,我开始使用riverpod_hooks,但我被卡住了。

目前我有一个提供者可以从 sqlite 获取数据:

final bloodPressureProvider = FutureProvider((_) => _findAllBloodPressures());
Future<List<BloodPressure>> _findAllBloodPressures() async {
  var _bloodPressure = BloodPressure.forSearchOnly();
  var result = await _bloodPressure.findAll();
  return result;
}

我可以成功使用它来渲染图表和显示列表:

class BloodPressureList extends HookWidget {

  @override
  Widget build(BuildContext context) {
    final bpList = useProvider(bloodPressureProvider);
    return Scaffold(
      drawer: NutriDrawer(context).drawer(),
      appBar: AppBar(
        title: Text('Blood Pressure History'),
      ),
      body: Column(
        children: [
          Container(
            padding: EdgeInsets.fromLTRB(0, 25, 15, 5),
            child: bpList.when(
                data: (bloodPressureList) => _buildLineChart(bloodPressureList),
                loading: () => CircularProgressIndicator(),
                error: (_, __) => Text('Ooooopsss error'),
            ),
          ),
          Expanded(
            child: bpList.when(
              data: (bloodPressureList) => _getSlidableListView(bloodPressureList, context),
              loading: () => CircularProgressIndicator(),
              error: (_, __) => Text('Ooopsss error'),
            ),
          ),
        ],
      ), ...

我目前遇到的问题是每当将新元素添加到数据库中时向小部件发出通知,这是在另一个屏幕/小部件中完成的,在使用提供程序之前我会使用 setState 但现在我知道我应该实现可能StateNotifier,但我缺少将其与从上述提供程序片段中使用的数据库返回的异步调用集成的正确方法。

非常感谢任何正确方向的指针。

更新解决方案:根据下面接受的答案,我使用了 context.refresh,它完全符合我的要求:

var result = Navigator.push(context, MaterialPageRoute(builder: (context) {
      return BloodPressureDetail(title, bloodPressure);
    }));
    result.then((_) => context.refresh(bloodPressureProvider));

因此,当从编辑/添加屏幕返回时,提供程序上下文会刷新,并且图表和列表的状态会自动更新。

【问题讨论】:

    标签: flutter riverpod flutter-hooks


    【解决方案1】:

    默认情况下,FutureProvider 会缓存未来的结果,因此只会在第一次访问时获取。 如果您想在每次进入屏幕时获取一个新值,请使用 FutureProvider.autoDispose。 如果您想手动刷新提供程序,您可以将 context.refresh(bloodPressureProvider) 与 FutureProvider 一起使用。

    如果您不想访问您的数据库以获取值但仍希望同步屏幕,您可以实现一个 stateNotifier 来代表您的数据库状态

    final dbState =
        StateNotifierProvider<dbState>((ProviderReference ref) {
      final dbState = DbState();
      dbState.init();
      return dbState;
    });
    
    class dbState extends StateNotifier<AsyncValue<List<String>>> {
       /// when the constructor is called the initial state is loading
       dbState() : super(AsyncLoading<List<String>>());
    
       /// fetch the values from the database and set the state to AsyncData 
       ///(could be good to add a try catch and set the sate to an error if one 
       /// occurs)
       void init()async{
           state = AsyncLoading<List<String>>();
           final fetchedValues = await fetchValues();
           state = AsyncData<List<String>>(fetchedValues);
       }
    
    }
    

    【讨论】:

    • 感谢使用 autodispose + context.refresh 正是我想要的。我将用解决方案更新我的问题。 TBH 除非真的有必要,否则我不会增加通知程序的额外复杂性。
    • 除非您显示其他人在数据库中添加的数据,否则无需执行 autoDispose + refresh,仅使用 refresh !只有在添加某些内容时才会访问数据库
    • 感谢@moulte 的提示,我会试试的。
    猜你喜欢
    • 1970-01-01
    • 2021-04-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-03
    • 1970-01-01
    • 1970-01-01
    • 2020-04-01
    相关资源
    最近更新 更多