flutter - 使用提供程序时在构建期间调用的 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()
提供程序代码。
这是什么意思以及如何解决问题?
解决方案
据我所知, notifyListeners() 将触发 setState() (除其他外),因此,当您productList.fetchProducts(_page);
在 initState() 函数中进行调用时,构建函数被调用得太早。
我通常在 的帮助下调用这些函数,WidgetsBinding.instance.addPostFrameCallback()
以确保所需的一切都可用于重新渲染。
推荐阅读
- html - 我无法将 LI 项目居中
- javascript - 删除 Firestore 中的嵌套引用
- excel - VBA 代码不运行,定义工作簿和工作表时出错
- javascript - 我可以使用 Angular 的日期管道格式化没有偏移的时区吗?
- python-3.x - 装饰器中的参数在装饰器范围内不可用?
- reactjs - 我可以在反应组件中调用反应组件吗
- django - 如何设置crispy_forms' Layout 以呈现精确到小数点后2 位的Django DecimalField?
- sql - SQL 将日期字段中的值转置为列
- react-native - 组件渲染时只打开一次 Realm 数据库(React Native)
- rest - RestTemplate 仅返回第一行,响应中缺少行