Reputation: 5819
I have the below Riverpod annotation for the provider. I would like to update the values in one page and get the updated value in next page.
@riverpod
class UserCardSheetInfo extends _$UserCardSheetInfo {
@override
UserCardInputSheet build() => const UserCardInputSheet(issuerKey: '', cardKey: '');
void updateIssuer(String value) {
state = state.copyWith(issuerKey: value);
print("issuerKey:${state.issuerKey}"); // has value
print("cardKey:${state.cardKey}"); // empty
}
void updateCard(String value) {
state = state.copyWith(cardKey: value);
print("issuerKey:${state.issuerKey}"); // empty
print("cardKey:${state.cardKey}"); // has value
}
}
@freezed
class UserCardInputSheet with _$UserCardInputSheet {
const factory UserCardInputSheet({
required String issuerKey,
required String cardKey,
}) = _UserCardInputSheet;
}
I the first page, I am updating the value as below.
class _SelectableIssuersList extends ConsumerStatefulWidget {
const _SelectableIssuersList();
@override
ConsumerState<_SelectableIssuersList> createState() => _SelectableCardsListState();
}
class _SelectableCardsListState extends ConsumerState<_SelectableIssuersList> {
@override
Widget build(BuildContext context) {
return SomeWidget(
onClick: (newIssuer) => setState(() {
ref.watch(userCardSheetInfoProvider.notifier).updateIssuer(newIssuer);
}),
);
}
}
In the next page, I am trying to read the updated value. But I am always getting an empty class without the values.
class _SelectableCardsList extends ConsumerStatefulWidget {
const _SelectableCardsList();
@override
ConsumerState<_SelectableCardsList> createState() => _SelectableCardsListState();
}
class _SelectableCardsListState extends ConsumerState<_SelectableCardsList> {
@override
Widget build(BuildContext context) {
// ====> Always Empty
print(ref.watch(userCardSheetInfoProvider).issuerKey);
return AnotherWidget();
}
}
How should I be handling the value read/write using Riverpod?
Upvotes: 0
Views: 165
Reputation: 5819
The issue is resolved after keeping the provider alive. This helped to keep the same state when navigating to other screens.
@Riverpod(keepAlive: true)
class UserCardSheetInfo extends _$UserCardSheetInfo {
@override
UserCardInputSheet build() => const UserCardInputSheet(issuerKey: '', cardKey: '');
void updateIssuer(String value) {
state = state.copyWith(issuerKey: value);
}
void updateCard(String value) {
state = state.copyWith(cardKey: value);
}
}
Upvotes: 0
Reputation: 126
riverpod is designed to handle immutable data and not mutable.
it does it by comparing the previous and the next states.
the problem with the line state.issuerKey = value
is that you change the previous state as well as the next so the comparison will always return true
and riverpod will not rebuild.
a correct implementation of your provider will be:
@riverpod
class UserCardSheetInfo extends _$UserCardSheetInfo {
@override
UserCardInputSheet build() => const UserCardInputSheet();
void updateIssuer(String value) {
state = state.copyWith(issuerKey: value);
}
void updateCard(String value) {
state = state.copyWith(cardKey: value);
}
}
class UserCardInputSheet {
const UserCardInputSheet({
this.issuerKey = '',
this.cardKey = '',
});
final String issuerKey;
final String cardKey;
UserCardInputSheet copyWith({
String? issuerKey,
String? cardKey,
}) => UserCardInputSheet(
issuerKey: issuerKey ?? this.issuerKey,
cardKey: cardKey ?? this.cardKey,
);
}
also, in your case, you don't need to use StatefullConsumerWidget
, ConsumerWidget
is enough
class _SelectableIssuersList extends ConsumerWidget {
const _SelectableIssuersList();
@override
Widget build(BuildContext context, WidgetRef ref) {
return SomeWidget(
onClick: (newIssuer) {
ref.read(userCardSheetInfoProvider.notifier).updateIssuer(newIssuer);
},
);
}
}
class _SelectableCardsList extends ConsumerWidget {
const _SelectableCardsList();
@override
Widget build(BuildContext context, WidgetRef ref) {
List<Cards> cards = ref.read(cardsProvider).requireValue;
print(ref.watch(userCardSheetInfoProvider).issuerKey);
return AnotherWidget();
}
}
Upvotes: 0