【问题标题】:flutter: Widgets are rebuilding even though `provider` is used颤振:即使使用了`provider`,小部件仍在重建
【发布时间】:2020-06-14 15:48:09
【问题描述】:

我正在使用provider 进行颤振状态管理。下面是我的代码

首页

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return DefaultTabController(
      length: 2,
      child: Scaffold(
        appBar: AppBar(
          //backgroundColor: Color.fromRGBO(0, 72, 100, 10),
          backgroundColor: Color.fromRGBO(25, 72, 114, 10),
          title: Text("something"),
          bottom: TabBar(
            indicatorColor: Colors.white70,
            labelStyle: TextStyle(
                fontFamily: 'Roboto-Regular',
                fontSize: 16.0,
                letterSpacing: 0.15),
            labelColor: Colors.white,
            labelPadding: EdgeInsets.all(5),
            tabs: <Widget>[
              Tab(
                text: "Fresh Products",
              ),
              Tab(
                text: "Frozen Products",
              ),
            ],
          ),
        ),
        body: Center(child: Home()),
      ),
    );
  }
}

class Home extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print("Home build methof");
    return TabBarView(
      children: <Widget>[
        Container(
          height: double.infinity,
          child: FutureBuilder(
            future: Provider.of<ProductSpeciesImpl>(context, listen: false)
                .getAllSpecies(),
            builder: (BuildContext context, AsyncSnapshot snapshot) {
              if (snapshot.connectionState == ConnectionState.waiting) {
                return Center(
                  child: Container(
                    child: Column(
                      mainAxisAlignment: MainAxisAlignment.center,
                      crossAxisAlignment: CrossAxisAlignment.center,
                      children: <Widget>[
                        CircularProgressIndicator(),
                        Container(
                          height: 10,
                        ),
                        Text(
                          "Loading Data... Please Wait",
                          style: Theme.of(context).textTheme.body1,
                        )
                      ],
                    ),
                  ),
                );
              } else {
                if (snapshot.hasError) {
                  return Center(
                    child: Text("An error Occured"),
                  );
                } else {
                  return Consumer<ProductSpeciesImpl>(
                      builder: (context, data, child) => GridView.builder(
                          physics:
                              ScrollPhysics(), // to disable GridView's scrolling
                          shrinkWrap: true,
                          itemCount: Provider.of<ProductSpeciesImpl>(context)
                              .productList
                              .length,
                          gridDelegate:
                              new SliverGridDelegateWithFixedCrossAxisCount(
                                  childAspectRatio:
                                      (MediaQuery.of(context).size.width *
                                          .5 /
                                          190),
                                  crossAxisCount: 2),
                          itemBuilder: (BuildContext context, int index) {
                            return GestureDetector(
                              onTap: () {
                                //print("sdsdsdsd");
                                // print(snapshot.data[index].name + " " + snapshot.data[index].idProductSpecies.toString() + " "+ snapshot.data[index].photo);
                                Navigator.pushNamed(context, "/products",
                                    arguments: {
                                      "name": Provider.of<ProductSpeciesImpl>(
                                              context,
                                              listen: false)
                                          .productList[index]
                                          .name,
                                      "id": Provider.of<ProductSpeciesImpl>(
                                              context,
                                              listen: false)
                                          .productList[index]
                                          .idProductSpecies,
                                      "photo": Provider.of<ProductSpeciesImpl>(
                                              context,
                                              listen: false)
                                          .productList[index]
                                          .photo
                                    });
                              },
                              child: Card(
                                elevation: 4.0,
                                shape: RoundedRectangleBorder(
                                    borderRadius: BorderRadius.circular(8.0)),
                                clipBehavior: Clip.antiAlias,
                                child: Column(
                                  mainAxisAlignment: MainAxisAlignment.start,
                                  children: <Widget>[
                                    Container(
                                      child: Text(
                                        Provider.of<ProductSpeciesImpl>(context,
                                                listen: false)
                                            .productList[index]
                                            .name,
                                      ),
                                    )
                                  ],
                                ),
                              ),
                            );
                          }));
                }
              }
            },
          ),
        ),

ProductSpeciesImpl

class ProductSpeciesImpl
    with ChangeNotifier
    implements ProductSpeciesInterface {
  NavLinks navLinks = NavLinks();

  List<ProductSpecies> productList = [];

  @override
  Future<void> getAllSpecies() async {
    var data = await http.get(navLinks.getAllProductSpecies());
    var jsonData = convert.json.decode(data.body).cast<Map<String, dynamic>>();

    try {
      productList = jsonData
          .map<ProductSpecies>((json) => new ProductSpecies.fromJson(json))
          .toList();

      print("Product sIZE: " + productList.length.toString());

      notifyListeners();
    } catch (error) {
      throw error;
    }
  }
}

代码运行良好。问题是每次我访问另一个页面并返回此页面时,UI 都会重新加载。我用过consumer,据我了解,consumer只会在调用时加载相关部分。这意味着我也不必在init 中运行我的产品加载代码。所以,我不明白为什么会这样。

感谢您对解决此问题的支持。

【问题讨论】:

    标签: android ios flutter flutter-layout flutter-provider


    【解决方案1】:

    您正在通过调用getAllSpecies() 在您的build() 函数中发起HTTP 请求。你不应该那样做。

    class Home extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        //...
              child: FutureBuilder(
                future: Provider.of<ProductSpeciesImpl>(context, listen: false)
                    .getAllSpecies(),
    
    

    build() 函数应该没有副作用。请将小部件转换为StatefulWidget 并在initState() 中加载。或者,让父 StatefulWidget 在其 initState() 中进行加载,并将数据传递给其构造函数中的此小部件。

    【讨论】:

    • 谢谢。我使用这种方式的原因是,在一个著名的教程中,他正在使用 futurebuilder 加载构建器,但令人惊讶的是没有重新加载!请您帮我理解这一点,consumerprovider 在页面重新加载时无法停止重建过程?
    • 如果在调用getAllSpecies() 时只返回Provider 中的现有数据会更好。一般来说,你应该可以处理很多 build() 调用,你的代码不应该依赖于 build() 是否被调用。
    • 好的。所以我将在initState 期间从服务器获取数据,并使用consumer 将这些“现有”数据加载到ListView。希望那很好?
    • errrr.. 我转换为有状态的,并注意到我的initstate 也会在您离开屏幕并返回时运行。实际上,我在标签上,在标签之间导航,
    • 我猜你可以在你的提供者类中做if (productList != null) loadProductList(),但这不是一个好方法。您的ProductSpeciesImpl 始终在加载,而从未使用过productList。如果我是你,我会放弃这个并使用pub.dev/documentation/provider/latest/provider/… 不要试图将 HTTP 加载与小部件事件联系起来。您的选项卡可以构建多次,您应该明确说明何时执行 HTTP 请求。这可能在包含选项卡的小部件的 initState 中。很抱歉之前的误导性投票。
    猜你喜欢
    • 2020-09-07
    • 2020-05-30
    • 2020-12-15
    • 1970-01-01
    • 2020-10-18
    • 2022-01-20
    • 2020-03-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多