How to read StateNotifierProvider.family without passing value?

408

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.

Share:
408
Viacheslav
Author by

Viacheslav

Updated on November 20, 2022

Comments

  • Viacheslav
    Viacheslav over 1 year

    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!

  • SalahAdDin
    SalahAdDin almost 3 years
    Actually, I'm doing the same, but still i have to pass the state provider with id to all widget children, and it looks unclean.
  • Viacheslav
    Viacheslav almost 3 years
    @SalahAdDin, you don't need to pass StateProvider to all widgets, but only to children, that require StateProvider, using Consumer or HookWidget.
  • SalahAdDin
    SalahAdDin almost 3 years
    That's why I'm doing actually, but it still looks ugly, hahahahha