【问题标题】:Flutter : using changeNotifier and provider when the context is not availableFlutter:在上下文不可用时使用 changeNotifier 和 provider
【发布时间】:2021-01-29 18:46:57
【问题描述】:

我正在尝试使用 Flutter 文档中描述的简单状态管理,使用 ChangeNotifier、Consumer 和 ChangeNotifierProvider。 我的问题是我无法获得有效的上下文来更新我的模型(详情如下......)。我收到一个错误:

错误:错误:在此 CreateOrganizationDialog 小部件上方找不到正确的提供程序

这可能是因为您使用的BuildContext 不包括您选择的提供者。有几种常见的情况:

  • 您尝试读取的提供程序位于不同的路径中。

提供者是“范围的”。因此,如果您在路由中插入提供程序,那么其他路由将无法访问该提供程序。

  • 您使用了 BuildContext,它是您尝试读取的提供程序的祖先。

确保 CreateOrganizationDialog 在您的 MultiProvider/Provider 下。 这通常发生在您创建提供程序并尝试立即读取它时。

以下是我的代码摘录:

    class OrganizationModel extends ChangeNotifier {
      final List<Organization> _items = [];
    
      /// An unmodifiable view of the items in the cart.
      UnmodifiableListView<Organization> get items => UnmodifiableListView(_items);
    
      void addList(List<Organization> items) {
        _items.addAll(items);
        notifyListeners();
      }
    }

这是我的模型。

    class OrganizationBodyLayout extends StatelessWidget {
    
      Future<void> _showCreateOrganizationDialog() async {
        return showDialog<void>(
            context: navigatorKey.currentState.overlay.context,
            barrierDismissible: false,
            child: CreateOrganizationDialog());
      }
    
      _onCreateOrganizationPressed() {
        _showCreateOrganizationDialog();
      }
    
      _onDeleteOrganizationPressed() {
        //TODO something
      }
    
      _onEditOrganizationPressed() {
        //TODO something
      }
    
      @override
      Widget build(BuildContext context) {
    
        return Container(
            child: Column(mainAxisSize: MainAxisSize.max, children: [
              ButtonBar(
                alignment: MainAxisAlignment.start,
                mainAxisSize: MainAxisSize.max,
                children: <Widget>[
                  RaisedButton(
                    onPressed: _onCreateOrganizationPressed,
                    child: Text("New Organization"),
                  ),
                ],
              ),
              Expanded(
                  child: Container(
                      color: Colors.pink,
                      child: Row(
                          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                          children: <Widget>[
                            Expanded(
                                child: ChangeNotifierProvider(
                                  create: (context) => OrganizationModel(),
                                  child: OrganizationListView(),
                                )),
                            Expanded(child: Container(color: Colors.brown))
                          ]))), 
            ]));
      }
    }

一个无状态小部件,它包含一个 ChangeNotifierProvider,它位于使用模型的列表小部件的顶部。 单击按钮时,会显示一个模式对话框,然后从网络中获取数据。然后我应该更新我的模型调用 addList 操作。 下面是有状态对话框的代码。

    class CreateOrganizationDialog extends StatefulWidget {
    @override
        _CreateOrganizationDialogState createState() =>
          _CreateOrganizationDialogState();
    }
    
    class _CreateOrganizationDialogState extends State<CreateOrganizationDialog> {
        TextEditingController _nametextController;
        TextEditingController _descriptionTextController;
    
        @override
        initState() {
            _nametextController = new TextEditingController();
            _descriptionTextController = new TextEditingController();
            super.initState();
        }
    
      @override
      Widget build(BuildContext context) {
        return Dialog(
            child: Container(
              width: 200,
              height: 220,
              child: Column(
                children: [
                  Text('New organization',
                      style: Theme.of(context).textTheme.headline6),
                  Padding(
                    padding: EdgeInsets.all(8.0),
                    child: TextFormField(
                      decoration: new InputDecoration(hintText: "Organization name"),
                      controller: _nametextController,
                    ),
                  ),
                  Padding(
                    padding: EdgeInsets.all(8.0),
                    child: TextFormField(
                      decoration:
                      new InputDecoration(hintText: "Organization description"),
                      controller: _descriptionTextController,
                    ),
                  ),
                  ButtonBar(
                    children: [
                      FlatButton(
                        child: new Text("Cancel"),
                        onPressed: () {
                          Navigator.of(context).pop();
                        },
                      ),
                      FlatButton(
                        child: new Text("Create"),
                        onPressed: () {
                          setState(() {
                            Future<Organization> organization =
                            backendCreateOrganization(_nametextController.text,
                                _descriptionTextController.text);
                            organization.then((value) {
                              Future<List<Organization>> organizations =
                              backendReloadOrganizations();
                              organizations.then((value) {
    
    
                                 var model = context.read<OrganizationModel>();
                                // var model = navigatorKey.currentState.overlay.context.read<OrganizationModel>();
                      
                                //model.addList(value);
                              });
                            });
                          });
                          Navigator.of(context).pop();
                          //context is the one for the create dialog here
                        },
                      )
                    ],
                  )
                ],
              ),
            ));
      }
    }

我的问题发生在生产线上

    var model = context.read<OrganizationModel>();

想想看,这里可用的上下文是模式对话框上下文 - 所以在小部件树中找不到提供程序是合乎逻辑的。 但是,我看不到如何检索正确的上下文(这将是提供者所在的结果列表视图的上下文)以获取模型然后更新它。

欢迎任何想法:-)

【问题讨论】:

    标签: flutter


    【解决方案1】:

    解决了(有点)。 我发现解决这个问题的唯一方法是让我的模型成为一个全局变量:

        var globalModel = OrganizationModel();
    

    并在所有使用它的小部件中引用这个全局模型。我找不到从另一个有状态小部件的回调中找到无状态小部件上下文的方法。

    它有效,但它很难看。仍然对优雅的解决方案持开放态度:-)

    【讨论】:

      【解决方案2】:

      Get_it 似乎是跨应用程序共享模型的优雅方式。请查看他们提供的不同用例的文档。

      您可以执行以下操作

      GetIt getIt = GetIt.instance;
      
      getIt.registerSingleton<AppModel>(AppModelImplementation());
      getIt.registerLazySingleton<RESTAPI>(() =>RestAPIImplementation());
      

      在代码的其他部分,您可以执行类似的操作

      var myAppModel = getIt.get<AppModel>();
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-07-20
        • 2020-11-03
        • 2020-02-29
        • 2020-11-23
        • 2021-11-12
        • 1970-01-01
        • 2020-12-17
        • 2021-01-13
        相关资源
        最近更新 更多