简体   繁体   English

如何在 initState 方法中访问 flutter 块?

[英]how to access flutter bloc in the initState method?

In the code shown below, the dispatch event is called from within the build method after getting the BuildContext object. What if I wish to do is to dispatch an event during processing at the start of the page within the initState method itself?在下面显示的代码中,在获取 BuildContext object 后从构建方法中调用调度事件。如果我想做的是在 initState 方法本身的页面开始处理期间调度事件怎么办?

If I use didChangeDependencies method, then I am getting this error: BlocProvider.of() called with a context that does not contain a Bloc of type FileManagerBloc.如果我使用 didChangeDependencies 方法,那么我会收到此错误: BlocProvider.of() called with a context that does not contain a Bloc of type FileManagerBloc. how to fix this?如何解决这个问题?

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: BlocProvider<FileManagerBloc>(
          builder: (context)=>FileManagerBloc(),
          child: SafeArea(
      child: Container(
          child: Column(
            children: <Widget>[
              Container(color: Colors.blueGrey, child: TopMenuBar()),
              Expanded(
                child: BlocBuilder<FileManagerBloc,FileManagerState>(
                  builder: (context , state){
                    return GridView.count(
                      scrollDirection: Axis.vertical,
                      physics: ScrollPhysics(),
                      crossAxisCount: 3,
                      crossAxisSpacing: 10,
                      children: getFilesListWidget(context , state),
                    );
                  },
                ),
              )
            ],
          ),
      ),
    ),
        ));
  }

  @override
  void dispose() {
    super.dispose();
  }

  @override
  void didChangeDependencies() {
    logger.i('Did change dependency Called');
    final FileManagerBloc bloc = BlocProvider.of<FileManagerBloc>(context) ;
    Messenger.sendGetHomeDir()
        .then((path) async {
      final files = await Messenger.sendListDir(path);
        bloc.dispatch(SetCurrentWorkingDir(path)) ;
        bloc.dispatch(UpdateFileSystemCacheMapping(path , files)) ;
    });
  }

The problem is that you are initializing the instance of FileManagerBloc inside the BlocProvider which is, of course inaccessible to the parent widget.问题是您正在BlocProvider内部初始化FileManagerBloc的实例,这当然是父小部件无法访问的。 I know that helps with automatic cleanup of the Bloc but if you want to access it inside initState or didChangeDependencies then you have to initialize it at the parent level like so,我知道这有助于自动清理Bloc但是如果您想在initStatedidChangeDependencies访问它,那么您必须像这样在父级初始化它,

FileManagerBloc _fileManagerBloc;

@override
void initState() {
  super.initState();
  _fileManagerBloc= FileManagerBloc();
  _fileManagerBloc.dispatch(LoadEducation());
}

@override
  Widget build(BuildContext context) {
    return Scaffold(
        body: BlocProvider<FileManagerBloc>(
          builder: (context)=> _fileManagerBloc,
          child: SafeArea(
      child: Container(
          child: Column(
            children: <Widget>[
              Container(color: Colors.blueGrey, child: TopMenuBar()),
              Expanded(
                child: BlocBuilder<FileManagerBloc,FileManagerState>(
                  builder: (context , state){
                    return GridView.count(
                      scrollDirection: Axis.vertical,
                      physics: ScrollPhysics(),
                      crossAxisCount: 3,
                      crossAxisSpacing: 10,
                      children: getFilesListWidget(context , state),
                    );
                  },
                ),
              )
            ],
          ),
      ),
    ),
        ));
  }

  @override
  void dispose() {
    _fileManagerBloc.dispose();
    super.dispose();
  }

  @override
  void didChangeDependencies() {
    logger.i('Did change dependency Called');
    Messenger.sendGetHomeDir()
        .then((path) async {
      final files = await Messenger.sendListDir(path);
        _fileManagerBloc.dispatch(SetCurrentWorkingDir(path)) ;
        _fileManagerBloc.dispatch(UpdateFileSystemCacheMapping(path , files)) ;
    });
  }

alternatively, if FileManagerBloc was provided/initialized at a grandparent Widget then it could easily be accessible at this level through BlocProvider.of<CounterBloc>(context);或者,如果FileManagerBloc是在祖父Widget提供/初始化的,那么可以通过BlocProvider.of<CounterBloc>(context);this级别轻松访问它BlocProvider.of<CounterBloc>(context);

Solution: Step 1: need apply singleton pattern on Bloc class解决方案:第一步:需要在Bloc class上应用singleton模式

class AuthBloc extends Bloc<AuthEvent, AuthState> {
  static AuthBloc? _instance;
  static AuthBloc get instance {
    if (_instance == null) _instance = AuthBloc();
    return _instance!;
  }
  ....
  ....

Step 2: use AuthBloc.instance on main.dart for Provider第 2 步:使用 main.dart 上的 AuthBloc.instance 作为 Provider

void main() async {
  runApp(MultiBlocProvider(
    providers: [
      BlocProvider(
        create: (context) => AuthBloc.instance,
      ),
      ...
      ...
    ],
    child: App(),
  ));
}

Now you can use Bloc without context现在您可以在没有上下文的情况下使用 Bloc

  1. you can get state by AuthBloc.instance.state from initState or anywhere您可以通过 AuthBloc.instance.state 从 initState 或任何地方获得 state
  2. you can add event from anywhere by AuthBloc.instance.add(..)你可以通过 AuthBloc.instance.add(..) 从任何地方添加事件
  3. you also call BlocA from another BlocB very simple您还可以非常简单地从另一个 BlocB 调用 BlocA

you can use it in didChangeDependencies method rather than initState .您可以在didChangeDependencies方法而不是initState使用它。

Example例子

 @override
  void didChangeDependencies() {
    final CounterBloc counterBloc = BlocProvider.of<CounterBloc>(context);
    //do whatever you want with the bloc here.
    super.didChangeDependencies();
  }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM