riverpod icon indicating copy to clipboard operation
riverpod copied to clipboard

Document the intended replacement for `copyWithPrevious`

Open timcreatedit opened this issue 5 months ago • 3 comments

I see that copyWithPrevious is being marked as internal. I use it every once in a while to allow my UI to stay in the data state when I trigger a mutation from a notifier. How would I do that in the future?


class SomeNotifier extends AsyncNotifier<int> {
    Future<int> build() {
        return 0;  
    }

    Future<void> add() async {
        if (state case final AsyncData data) {
            state = AsyncLoading().copyWithPrevious(data);
            // API call or something
            await Future.delayed(Duration(seconds:1));
            state = AsyncData(data.value++);
        }
    }
}

https://github.com/rrousselGit/riverpod/blob/c1322dcc2b05ebed5c172e6c546e48fc29ce51ec/packages/riverpod/lib/src/core/async_value.dart#L575-L579

timcreatedit avatar Sep 02 '25 14:09 timcreatedit

The API wasn't meant to be public.

I am not sure about the replacement yet. But in the meantime, you can call state= twice. This should achieve similar effect:

state = AsyncData(data);
state = AsyncLoading();

rrousselGit avatar Sep 03 '25 18:09 rrousselGit

Adding to that, the copyWithPrevious in your example was useless :).
Riverpod ignored it when inside Stream/AsyncNotifiers.

rrousselGit avatar Sep 03 '25 18:09 rrousselGit

The API wasn't meant to be public.

I am not sure about the replacement yet. But in the meantime, you can call state= twice. This should achieve similar effect:

state = AsyncData(data); state = AsyncLoading();

This will probably not work as a replacement in most cases.


I also use copyWithPrevious like this.

class A extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final asyncValue = ref.watch(provider);

    return asyncValue.when(
      data: (data) {
        return ListView(
          children: [
            if (asyncValue.isLoading) LinearProgressIndicator()
            ...
          ],
        );
      },
      ...
    );
  }
}

It is a simple option to show data with a loading indicator (AsyncData with isLoading=true). One use case is pagination, as shown here.


Possible solutions

  1. Use loading state
state = AsyncLoading();

and handle this in the ui as loading with data (AsyncLoading with hasValue=true). This does not feel right as data is now also handled in the loading case.

 return asyncValue.when(
  ....
  loading: () {
    if(asyncValue.hasValue) {
      return ListView(
        children: [
          if (asyncValue.isLoading) LinearProgressIndicator()
          ...
        ],
      );
    }
  },
);
  1. Use the new mutation api See https://riverpod.dev/docs/concepts2/mutations

  2. #4172 (in future)

snapsl avatar Sep 11 '25 10:09 snapsl