Purus
Purus

Reputation: 5819

Update and Read State of a Class using RiverPod Notifier

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

Answers (2)

Purus
Purus

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

Shlomo Cardoso
Shlomo Cardoso

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

Related Questions