首页 > 解决方案 > 使用提供程序时在构建期间调用的 setState() 或 markNeedsBuild()

问题描述

我正在尝试在 Flutter 中使用提供程序。这是提供者代码:

class SortBy{
String value;
String text;
String sortOrder;

SortBy(this.value, this.text, this.sortOrder);
}


 enum LoadMoreStatus {INITIAL, LOADING, STABLE}

 class ProductProvider with ChangeNotifier {

 APIServices _apiServices;
 List<Product> _productList;
 SortBy _sortBy;

 int pageSize = 10;

  List<Product> get allProducts => _productList;

 double get totalRecords => _productList.length.toDouble();

 LoadMoreStatus _loadMoreStatus = LoadMoreStatus.STABLE;
 getLoadMoreStatus() => _loadMoreStatus;

 ProductProvider(){
   resetStreams();
   sortBy = SortBy("modified", "Latest", "asc");
  }

 void resetStreams(){
    _apiServices = APIServices();
   _productList = List<Product>();

 }

 setLoadingState(LoadMoreStatus loadMoreStatus){
    _loadMoreStatus = loadMoreStatus;
    notifyListeners();
  }

  setSortOrder(SortBy sortBy){
     _sortBy = sortBy;
   notifyListeners();
  }


  fetchProducts(pageNumber, {
     String strSearch,
     String tagName,
     String categoryId,
     String sortBy,
     String sortOrder = "asc",
   })async{
    List<Product> itemModel = await _apiServices.getProducts(
     strSearch: strSearch,
      tagName: tagName,
      pageNumber: pageNumber,
      pageSize: this.pageSize,
      categoryId: categoryId,
      sortBy: this._sortBy.value,
      sortOrder: this._sortBy.sortOrder

     );

    if(itemModel.length > 0){
      _productList.addAll(itemModel);
     }

     setLoadingState(LoadMoreStatus.STABLE);
    notifyListeners();
  }
}

这是我使用提供程序代码的代码:

class _ProductPageState extends BasePageState<ProductPage> {
int _page = 1;
ScrollController _scrollController = new ScrollController();
final _sortByOptions = [
  SortBy("popularity", "Popularity", "asc"),
  SortBy("modified", "Latest", "asc"),
  SortBy("price", "Price: High to Low", " desc"),
  SortBy("price", "Price: Low to High", "asc"),
];
@override
void initState() {
  var productList = Provider.of<ProductProvider>(context, listen: false);
  productList.resetStreams();
  productList.setLoadingState(LoadMoreStatus.INITIAL);
  productList.fetchProducts(_page);

  _scrollController.addListener(() {
    if (_scrollController.position.pixels ==
        _scrollController.position.maxScrollExtent) {
      productList.setLoadingState(LoadMoreStatus.LOADING);
      productList.fetchProducts(++_page);
    }
  });
}

Widget pageUI() {
  return _productList();
}

Widget _productList() {
  return new Consumer<ProductProvider>(
      builder: (context, productsModel, child) {
    if (productsModel.allProducts != null &&
        productsModel.allProducts.length > 0 &&
        productsModel.getLoadMoreStatus() != LoadMoreStatus.INITIAL) {
      return _buildList(productsModel.allProducts, productsModel.getLoadMoreStatus() == 
       LoadMoreStatus.LOADING);
    }
    return Center(
      child: CircularProgressIndicator(),
    );
  });
}

 Widget _buildList(List<Product> items, bool isLoadMore) {
   return Column(
    children: [
      _productFilters(),
      Flexible(
          child: GridView.count(
        shrinkWrap: true,
        controller: _scrollController,
        crossAxisCount: 2,
        physics: ClampingScrollPhysics(),
        scrollDirection: Axis.vertical,
        children: items.map((Product item) {
           return ProductCard(
            data: item,
          );
        }).toList(),
      )
      ),
      Visibility(
           child: Container(
            padding: EdgeInsets.all(5),
            height: 35,
            width: 35,
            child: CircularProgressIndicator(),
          ),
        visible: isLoadMore,
      )
    ],
  );
}

Widget _productFilters() {
  return Container(
    height: 51,
    margin: EdgeInsets.fromLTRB(10, 10, 10, 5),
    child: Row(
    children: [
      Flexible(
          child: TextField(
        decoration: InputDecoration(
          prefixIcon: Icon(Icons.search),
          hintText: "Search",
          border: OutlineInputBorder(
              borderRadius: BorderRadius.circular(15),
              borderSide: BorderSide.none),
          fillColor: Colors.white38,
          filled: true,
        ),
      )),
      SizedBox(
        width: 15,
      ),
      Container(
        decoration: BoxDecoration(
          color: Color(0xffe6e6ec),
          borderRadius: BorderRadius.circular(9),
        ),
        child: PopupMenuButton(
          onSelected: (sortBy) {


          },
          itemBuilder: (BuildContext context) {
            return _sortByOptions.map((item) {
              return PopupMenuItem(
                child: Container(child: Text(item.text)),
              );
            }).toList();
          },
          icon: Icon(Icons.tune),
        ),
      )
    ],
  ),
);
}
}

我收到一条错误消息:

在构建期间调用的 setState() 或 markNeedsBuild()。

错误消息指向notifyListeners()提供程序代码。

这是什么意思以及如何解决问题?

标签: flutterrestflutter-provider

解决方案


据我所知, notifyListeners() 将触发 setState() (除其他外),因此,当您productList.fetchProducts(_page); 在 initState() 函数中进行调用时,构建函数被调用得太早。

我通常在 的帮助下调用这些函数,WidgetsBinding.instance.addPostFrameCallback()以确保所需的一切都可用于重新渲染。


推荐阅读