#flutter #flutter-provider #flutter-hive
Вопрос:
Я использую Hive для хранения всего списка Card
элементов, связанных с an Extension
. На экране выбранного расширения я показываю карточки этого расширения с кучей фильтров/сортировки.
Для этого я использую ValueListenableBuilder
, чтобы получить текущее расширение и их карты.
И когда я фильтрую/сортирую этот список, я хочу сохранить их в своем Provider
классе, потому что я хотел бы повторно использовать этот список на другом экране.
Но мы это делаем context.read<ShowingCardsProvider>().setAll(sortedList)
, я получил эту ошибку:
setState() or markNeedsBuild() called during build.
Я ShowingCardsProvider
пока ничего не слушаю.
Не могли бы вы объяснить мне, что здесь не так?
Спасибо!
главная.дротик
runApp(MultiProvider(
providers: [
ChangeNotifierProvider.value(value: AuthProvider()),
ChangeNotifierProvider.value(value: UserProvider()),
ChangeNotifierProvider.value(value: ShowingCardsProvider()),
],
child: MyApp(),
));
showing_cards_provider.dart
import 'dart:collection';
import 'package:flutter/material.dart';
import 'package:pokecollect/card/models/card.dart';
class CardsProvider extends ChangeNotifier {
final List<CardModel> _items = [];
UnmodifiableListView<CardModel> get items => UnmodifiableListView(_items);
void setAll(List<CardModel>? items) {
_items.clear();
if (items != null || items!.isNotEmpty) {
_items.addAll(items);
}
notifyListeners();
}
void addAll(List<CardModel> items) {
_items.addAll(items);
notifyListeners();
}
void removeAll() {
_items.clear();
notifyListeners();
}
}
extension_page.dart
@override
Widget build(BuildContext context) {
return Scaffold(
extendBodyBehindAppBar: true,
body: SafeArea(
child: LayoutBuilder(builder: (context, constraints) {
return CustomScrollView(
slivers: [
SliverAppBar(
...
),
...
SliverPadding(
padding: EdgeInsets.symmetric(horizontal: 16.0),
sliver: ValueListenableBuilder(
valueListenable: ExtensionBox.box.listenable(keys: [_extensionUuid]),
builder: (ctx, Box<Extension> box, child) {
List<CardModel>? cardsList = box
.get(_uuid)!
.cards
?.where((card) => _isCardPassFilters(card))
.cast<CardModel>()
.toList();
var sortedList = _simpleSortCards(cardsList);
context.read<ShowingCardsProvider>().setAll(sortedList);
return _buildCardListGrid(sortedList);
},
),
),
]
);
}),
),
);
}
Ответ №1:
Это действительно потому, что я использую ValueListenableBuilder
и, пока виджет создается, notifyListeners
вызывается (в моего провайдера).
Мое исправление состоит в том, чтобы сделать это:
return Future.delayed(
Duration(milliseconds: 1),
() => context.read<ShowingCardsProvider>().setAll(list),
);
Не очень красиво, но это работает 😅
Если у вас есть более элегантный способ, не стесняйтесь комментировать его!