Search code examples
flutterdartproviderriverpod

How to read StateNotifierProvider.family without passing value?


I have implemented StateNotifierProvider with ".family" modifier:

class OrderReviewNotifier extends StateNotifier<OrderReviewState> {
  final OrderReviewRepository repository;

  OrderReviewNotifier(
    this.repository,
    int orderId,
  ) : super(OrderReviewState.initial(orderId));

  Future<void> getOrderItems() async {
    //.....
  }
}

final orderReviewProvider = StateNotifierProvider.autoDispose
    .family<OrderReviewNotifier, OrderReviewState, int>(
  (ref, orderId) {
    return OrderReviewNotifier(
      ref.watch(orderReviewRepositoryProvider),
      orderId,
    );
  },
);

Then in Consumer I watch it:

        Consumer(
            builder: (context, watch, child) {
              
              final state = watch(orderReviewProvider(order.id));

             //.....
            },
          );

But when I want to read it, I need to pass order.id too:

                  onTap: () {
                    context
                        .read(orderReviewProvider(order.id).notifier)
                        .getOrderItems();
                  },

When I want to send events to notifier from another file, I don't have order.id. How to get out of this situation? Thanks for any help!


Solution

  • I figured out. All I needed was StateProvider.

    final selectedOrderProvider = StateProvider<Order?>((ref) => null);
    

    Then in orderReviewProvider I can easily get orderId.

    final orderReviewProvider =
        StateNotifierProvider.autoDispose<OrderReviewNotifier, OrderReviewState>(
      (ref) {
        return OrderReviewNotifier(
          ref.read,
          orderId: ref.watch(selectedOrderProvider).state!.id,
          repository: ref.watch(orderReviewRepositoryProvider),
        );
      },
    );
    
    
    class OrderReviewNotifier extends StateNotifier<OrderReviewState> {
      OrderReviewNotifier(
        this.read, {
        required int orderId,
        required this.repository,
      }) : super(OrderReviewState.initial(orderId)) {
        getOrderItems();
      }
    
      final Reader read;
    
      final OrderReviewRepository repository;
    
      Future<void> getOrderItems() async {
        state = state.copyWith(
          isLoading: true,
          error: null,
        );
        final result = await repository.getOrderItems(state.orderId);
        final checkedItemIds = await repository.getCheckedItemIds(state.orderId);
    
        if (!mounted) {
          return;
        }
    
        result.when(
          data: (data) {
            final isAllItemsChecked = !checkedItemIds.containsValue(false) &&
                checkedItemIds.length >= data.length;
    
            state = state.copyWith(
              orderItems: data,
              checkedItemIds: checkedItemIds,
              isAllItemsChecked: isAllItemsChecked,
            );
          },
          error: (message) {
            state = state.copyWith(
              error: message,
            );
          },
        );
    
        state = state.copyWith(
          isLoading: false,
        );
      }
    }
    

    The documentation describes the work with this well: link.