Reputation: 201
I have 2 providers. The one that deals with selected filters:
final filtersProvider = StateProvider.autoDispose<List<String>>(
(ref) => [],
);
And the other that receives data. It's observes the filters value.
final priceResponseProvider =
FutureProvider.autoDispose.family<PriceResponse, GetPriceParams>(
(ref, params) {
// This should update [priceResponseProvider]
// every time when [filtersProvider] changes.
// But it does not
final filters = ref.watch(filtersProvider);
return ref
.read(priceFetcherProvider)
.search(params.copyWith(filterBrands: filters));
},
);
Besides I have 2 screens.
class PricePage extends ConsumerWidget {
const PricePage({required this.params, super.key});
static void navigate(
BuildContext context, {
required GetPriceParams params,
}) =>
context.pushNamed(name, extra: params);
final GetPriceParams params;
static const name = 'price_page';
static const path = '/price_page';
@override
Widget build(BuildContext context, WidgetRef ref) {
final searchResult = ref.watch(priceResponseProvider(params));
return Scaffold(
body: searchResult.when(
loading: () => const LoadingWidget(),
error: (e, __) => Text((e as CustomException).message ?? ''),
data: (PriceResponse resp) {
final titles = resp.result.map((e) => e.caption).toList();
final items = ref.watch(priceGroupsProvider(resp));
return Scaffold(
appBar: AppBarWidget(
title: _title,
image: AppImages.filter,
onTap: () async {
// Navigates to PriceFiltersPage and returns selected filters
final filters = await PriceFiltersPage.navigate(
context,
model: PriceFiltersPageModel(
brands: resp.brands.map((e) => e.brand).toList(),
initialSelected: ref.read(filtersProvider),
),
);
if (filters == null) return;
// Updates provider with selected filters
ref.read(filtersProvider.notifier).state = filters;
},
),
body: PriceListView(items: items)
);
},
),
);
}
}
class PriceFiltersPageModel {
PriceFiltersPageModel({
required this.brands,
required this.initialSelected,
});
final List<String> brands;
final List<String> initialSelected;
}
class PriceFiltersPage extends StatefulWidget {
const PriceFiltersPage({required this.model, super.key});
static const String name = 'price_filters';
static const String path = '/price_filters';
final PriceFiltersPageModel model;
static Future<List<String>?> navigate(
BuildContext context, {
required PriceFiltersPageModel model,
}) async =>
context.pushNamed(name, extra: model);
@override
State<PriceFiltersPage> createState() => _PriceFiltersPageState();
}
class _PriceFiltersPageState extends State<PriceFiltersPage> {
late List<String> selected = widget.model.initialSelected;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBarWidget(
title: 'Фильтры',
stageText: 'Сбросить',
onLeadingButtonTap: () {},
),
body: Padding(
padding: AppDecoration.padding,
child: SafeArea(
child: Stack(
children: [
SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.only(top: 24, bottom: 90),
child: Column(
children: [
_TitleWidget(
title: 'Бренд',
onResetTap: () {},
),
const SizedBox(height: 12),
FiltersChoiceChipWidget(
titles: widget.model.brands,
initialSelectedValues: widget.model.initialSelected,
onSelectedValues: (values) {
selected = values;
},
),
],
),
),
),
// КНОПКА ПРИМЕНИТЬ
Positioned(
left: 16,
right: 16,
bottom: 20,
child: MainButton(
title: 'Применить',
onTap: () {
// returns selected filters
context.pop(selected);
},
),
),
],
),
),
),
);
}
}
I want to update priceResponseProvider every time when filtersProvider changes. However for some reason it does not executes when I change value filtersProvider.
I tried to to assign filtersProvider inside PriceFiltersPage, the same result. I also tries to listen to filtersProvider updates inside the PricePage but the listener does not executes.
Appreciate any help
Upvotes: 0
Views: 66
Reputation: 8529
You passed the result of ref.read(filtersProvider)
to PriceFiltersPage
, which is a List<String>
, and the page return the same List
even though the elements might have been modified. Riverpod doesn't know those changes since the List
refers to the same List
that the provider previously has. Although this might not be the best practice, but as a quick fix you can pass your list to the page like this:
final filters = await PriceFiltersPage.navigate(
context,
model: PriceFiltersPageModel(
brands: resp.brands.map((e) => e.brand).toList(),
initialSelected: [...ref.read(filtersProvider)],
),
);
Please see the StateNotifierProvider
documentation for the good practice on how to handle list in a provider.
Upvotes: 1