skip to Main Content

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?

2

Answers


  1. Chosen as BEST ANSWER

    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);
      }
    }
    

  2. 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();
      }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search