如何在initState中调用cubit类中的函数?

Posted

技术标签:

【中文标题】如何在initState中调用cubit类中的函数?【英文标题】:How to call a function in cubit class in initState? 【发布时间】:2021-12-17 11:21:29 【问题描述】:

所以,我在 Cubit 类中做了一个函数,它是从 API 获取数据。现在,如果我按下一个按钮,我就可以获得数据。我想在页面/屏幕打开时自动调用该功能。供您参考,此页面是用户打开应用程序时将启动的第一个页面。这是我的一些代码。

class UsersCubit extends Cubit<UsersState> 
  UsersCubit() : super(UsersInitial());

  UserRepository _userRepository = UserRepository();

  void getAllUsers() async
    emit(UsersLoading());
    try
      ResponseUsers _data = await _userRepository.getUsers();
      emit(UsersSuccess(_data));
     catch(e)
      emit(UsersError(e.toString()));
    
  

class UsersPage extends StatefulWidget 
  const UsersPage(Key? key) : super(key: key);

  @override
  _UsersPageState createState() => _UsersPageState();


class _UsersPageState extends State<UsersPage> 

  @override
  Widget build(BuildContext context) 
    return Scaffold(
      appBar: AppBar(title: Text("Users")),
      body: BlocProvider(
        create: (context) => UsersCubit(),
        child: BlocConsumer<UsersCubit, UsersState>(
          listener: (context, state) 
            if(state is UsersLoading)
              print("getting users ...");
             else if (state is UsersSuccess)
              print(state.data.users[1].identity!.name);
             else if (state is UsersError)
              print(state.errorMessage);
            
          ,
          builder: (context, state) 
            return Stack(
              children: [
                (state is UsersSuccess) ? listViewUsers(state.data.users) : progressBar(),
                ElevatedButton(
                  onPressed: ()
                    context.read<UsersCubit>().getAllUsers();
                  ,
                  child: Text("GET USERS"),
                )
              ],
            );
          ,
        ),
      ),
    );
  

我曾尝试直接在initState 中调用该函数,但是当我运行该应用程序时它会返回错误。

  @override
  void initState() 
    context.read<UsersCubit>().getAllUsers();
    super.initState();
  

错误:

Error: Could not find the correct Provider<UsersCubit> above this UsersPage Widget

This happens because you used a `BuildContext` that does not include the provider
of your choice. There are a few common scenarios:

- You added a new provider in your `main.dart` and performed a hot-reload.
  To fix, perform a hot-restart.

- The provider you are trying to read is in a different route.

  Providers are "scoped". So if you insert of provider inside a route, then
  other routes will not be able to access that provider.

- You used a `BuildContext` that is an ancestor of the provider you are trying to read.

  Make sure that UsersPage is under your MultiProvider/Provider<UsersCubit>.
  This usually happens when you are creating a provider and trying to read it immediately.

  For example, instead of:

  ...
  Widget build(BuildContext context) 
    return Provider<Example>(
      create: (_) => Example(),
      // Will throw a ProviderNotFoundError, because `context` is associated
      // to the widget that is the parent of `Provider<Example>`
      child: Text(context.watch<Example>()),
    ),
  
  ...

  consider using `builder` like so:

  ...
  Widget build(BuildContext context) 
    return Provider<Example>(
      create: (_) => Example(),
      // we use `builder` to obtain a new `BuildContext` that has access to the provider
      builder: (context) 
        // No longer throws
        return Text(context.watch<Example>()),
      
    ),
  

有什么办法可以解决这个问题吗?

【问题讨论】:

你能分享你的代码吗?哪个有 BlocProvider for UsersCubit 和 class 使用这个 Cubit ? 由于您使用的是 Cubit,因此您被锁定在 BloC 中。如此简短的回答:我帮不了你。更长的答案:如果 BloC 是您与 Flutter 一起使用的 ONLY 状态管理,那么 PLEASE 考虑替代方法。很多时候,你不需要比StatefulWidget 更复杂的东西。你SELDOM需要比Provider更复杂的东西。 Flutter 提供了很多 - 很棒! - 选择。使用“工作的最佳工具”:) PS:when I run the app it returns an error...:请更新您的帖子,提供准确的错误信息! 我已经更新了@dangngocduc 的帖子 MaterialApp 上方提供您的cubit,您可以从应用程序内的任何位置访问它。 【参考方案1】:

您可以尝试将BlocConsumer 包裹在Builder 中吗?

import 'package:flutter/material.dart';

class UsersPage extends StatefulWidget 
  const UsersPage(Key? key) : super(key: key);

  @override
  _UsersPageState createState() => _UsersPageState();


class _UsersPageState extends State<UsersPage> 

  @override
  Widget build(BuildContext context) 
    return Scaffold(
      appBar: AppBar(title: Text("Users")),
      body: BlocProvider(
        create: (context) 
          final cubit = UsersCubit();
          cubit.getAllUsers();
          return cubit;
        ,
        child: Builder(builder: (context) 
          return BlocConsumer<UsersCubit, UsersState>(
            listener: (context, state) 
              if(state is UsersLoading)
                print("getting users ...");
               else if (state is UsersSuccess)
                print(state.data.users[1].identity!.name);
               else if (state is UsersError)
                print(state.errorMessage);
              
            ,
            builder: (context, state) 
              return Stack(
                children: [
                  (state is UsersSuccess) ? listViewUsers(state.data.users) : progressBar(),
                  ElevatedButton(
                    onPressed: ()
                      context.read<UsersCubit>().getAllUsers();
                    ,
                    child: Text("GET USERS"),
                  )
                ],
              );
            ,
          );
        ),
      ),
    );
  


【讨论】:

我刚试了一下,还是一样的错误 我刚刚更新了解决方案,你可以再试试我的代码吗? 这个案子已经解决了:)【参考方案2】:

我在@Ehsan Askari 的帮助下解决了这个问题。他建议我提供MaterialApp上方的肘部,然后我就做了。这是我现在的代码

class AppWidget extends StatelessWidget 
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) 
    return BlocProvider(
      create: (context) => UsersCubit(),
      child: MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: UsersPage(),
      ),
    );
  

class UsersPage extends StatefulWidget 
  const UsersPage(Key? key) : super(key: key);

  @override
  _UsersPageState createState() => _UsersPageState();


class _UsersPageState extends State<UsersPage> 

  @override
  void initState() 
    context.read<UsersCubit>().getAllUsers();
    super.initState();
  

  @override
  Widget build(BuildContext context) 
    return Scaffold(
      appBar: AppBar(title: Text("Users")),
      body: BlocConsumer<UsersCubit, UsersState>(
        listener: (context, state) 
          if(state is UsersLoading)
            print("getting users ...");
           else if (state is UsersSuccess)
            print(state.data.users[1].identity!.name);
           else if (state is UsersError)
            print(state.errorMessage);
          
        ,
        builder: (context, state) 
          return (state is UsersSuccess) ? listViewUsers(state.data.users) : progressBar();
        ,
      ),
    );
  

【讨论】:

以上是关于如何在initState中调用cubit类中的函数?的主要内容,如果未能解决你的问题,请参考以下文章

如何在使用 pop 时重新加载或调用一些函数 initState()

如何在flutter中调用initState中的异步方法

Flutter BLoC 库:将 TextEditingController 对象保存在哪里:在 State、BLoC / Cubit 类中还是在小部件中?

颤振异步调用不会在 initState() 中异步运行

Flutter 中的 initState 和类构造函数有啥区别?

从 blocbuilder 接收值的 initstate 中的 BlocProvider