Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Riverpod v2: ref.watch, ScopedProvider, and misc changes #49

Merged
merged 52 commits into from
Aug 2, 2020

Conversation

rrousselGit
Copy link
Owner

@rrousselGit rrousselGit commented Jul 15, 2020

  • Breaking: Rename ProviderStateOwnerObserver -> ProviderObserver, as a follow up to the previous point.

  • Breaking: Remove the ability to override a provider for only a part of the widget tree (but still allow overriding a provider for the entire app)
    The ability to override a provider for only one widget is useful only in some limited situations and relatively dangerous.
    Worse, this feature prevents implementing more useful ones. Removing it unblocks this limitation.

  • Breaking: Remove Computed (which is fused with Provider)

  • Breaking: rename myProvider.overrideAs into .overrideWithProvider

  • add myProvider.overrideWithValue(42) (and handle value change)

  • Breaking remove StreamProvider/FutureProvider.debugOverrideWithValue

  • Add a ref.watch, which causes all providers to rebuild the value created when the watched value changes (like Computed, but for everything)

  • Make Provider filter updates if, on recreation after a ref.watch, the value created is == to before (like Computed)

  • Breaking: Make ref.read(FutureProvider<int>) return AsyncValue<int> instead of Future<int>

  • // for StreamProvider

  • Add a FutureProvider.future, which allows reading the Future<T> instance:
    ```dart
    final firstProvider =FutureProvider((ref) async => 42);
    final second = FutureProvider((ref) async {
    final first = await ref.watch(firstProvider.future); // 42
    return first * 2; // 84
    });

  • // for StreamProvider.stream

  • Breaking provider.read(context) => context.read(provider)

  • Implement .retry modified Implement a "Retry" feature #42

  • Breaking removed ref.dependOn

  • Breaking change provider.readOwner(container) into container.read(provider)

  • Breaking change provider.watchOwner(container) into container.watch(provider)

  • Breaking change provider.read(context) into context.read(provider).
    This is more intuitive, as instead of wondering "why is there no provider.read?", when we write context.read(provider) we will get a compilation error.

  • ((requires removing local overrides) Have the .family.autoDispose combination of providers destroys the keys used when no-longer listened.
    This will avoid memory leaks (although minor).

  • Add StreamProvider.last, to obtain a Future<T> that resolves with the latest value exposed.

  • Add a ScopedProvider, which is a new kind of provider, that expose a value which can be overridden locally in the widget tree.
    This provider would not have a StateNotifier/Stream/... variant.
    This is similar to InheritedWidgets/package:provider, but used like riverpod providers:

    final productId = ScopedProvider<int>(null);
    ...
    ListView(
      children: [
        ProviderScope(
          overrides: [
            productId.overrideAs(0)
          ],
          child: Item(),
        ),
        ProviderScope(
          overrides: [
            productId.overrideAs(1)
          ],
          child: Item(),
        ),
      ],
    ),
    ...
    // inside Item
    Widget build(context) {
      final itemId = useProvider(productId);
    }

    It is not possible for ref.read to read a ScopedProvider.
    Only useProvider & Consumer can do so.

    This should solve the existing use-cases for local overrides of providers, without blocking the implementation of a ComputeFuture & co.

  • Allow passing a custom ProviderContainer to the top-most ProviderScope

  • **Breaking ref.read(Provider.autoDispose()) no-longer compiles – use ref.watch instead

@codecov
Copy link

codecov bot commented Jul 15, 2020

Codecov Report

Merging #49 into master will decrease coverage by 3.89%.
The diff coverage is 94.89%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master      #49      +/-   ##
==========================================
- Coverage   99.05%   95.15%   -3.90%     
==========================================
  Files           7       29      +22     
  Lines         212      847     +635     
==========================================
+ Hits          210      806     +596     
- Misses          2       41      +39     
Impacted Files Coverage Δ
packages/riverpod/lib/src/common.dart 93.75% <ø> (ø)
.../riverpod/lib/src/state_provider/auto_dispose.dart 0.00% <0.00%> (ø)
...riverpod/lib/src/stream_provider/auto_dispose.dart 73.33% <73.33%> (ø)
...riverpod/lib/src/state_notifier_provider/base.dart 80.95% <80.95%> (ø)
...ter_riverpod/lib/src/change_notifier_provider.dart 83.33% <83.33%> (ø)
...kages/riverpod/lib/src/framework/auto_dispose.dart 92.68% <86.95%> (ø)
...ges/riverpod/lib/src/framework/value_provider.dart 90.90% <90.90%> (ø)
packages/riverpod/lib/src/framework/container.dart 94.21% <94.21%> (ø)
...ages/riverpod/lib/src/framework/base_provider.dart 98.52% <98.49%> (ø)
...lib/src/change_notifier_provider/auto_dispose.dart 100.00% <100.00%> (ø)
... and 47 more

@rrousselGit rrousselGit added the enhancement New feature or request label Jul 15, 2020
@smiLLe
Copy link

smiLLe commented Jul 15, 2020

Breaking: No longer destroy the state of a Computed when no-longer-used. Instead, the Computed is simply "paused".

Does this mean we are able to dependOn the Computed in non Computed Providers?

@rrousselGit
Copy link
Owner Author

Does this mean we are able to dependOn the Computed in non Computed Providers?

No (Well, you could, but couldn't read the value).

It's about useProvider(computed) mostly. If all widgets stops listening to a computed, it is destroyed.

@mono0926
Copy link
Sponsor Contributor

mono0926 commented Jul 15, 2020

[Edited] fixed


itemIndex isn't used and productId isn't defined, is this mistake?

final itemIndex = ScopedProvider<int>(null);
...
ListView(
  children: [
    ProviderScope(
      overrides: [
        productId.overrideAs(0)
      ],
      child: Item(),
    ),
    ProviderScope(
      overrides: [
        productId.overrideAs(1)
      ],
      child: Item(),
    ),
  ],
),
...
// inside Item
Widget build(context) {
  final itemId = useProvider(productId);
}

@rrousselGit
Copy link
Owner Author

itemIndex isn't used and productId isn't defined, is this mistake?

Good catch, fixed (itemIndex -> productId)

* Throw if a provider is overriden in a non-root container

* Merge _computedStateReader with _stateReader
Simplify _readProviderState

* Can no-longer do overrides: [provider]

* remove dead code
@rrousselGit
Copy link
Owner Author

Thinking about it, instead of "ComputedChangeNotifier", I'll allow providers to "watch" to another provider

Then Computed == Provider

Before:

final computed = Computed((read) {
  return Whatever(read(anotherProvider));
});

After:

final computed = Provider((ref) {
  return Whatever(ref.watch(anotherProvider));
});

@RobertBrunhage
Copy link
Contributor

RobertBrunhage commented Jul 16, 2020

Thinking about it, instead of "ComputedChangeNotifier", I'll allow providers to "watch" to another provider

Then Computed == Provider

Before:

final computed = Computed((read) {
  return Whatever(read(anotherProvider));
});

After:

final computed = Provider((ref) {
  return Whatever(ref.watch(anotherProvider));
});

I would prefer this option instead of having a Computed. It makes more sense to me to just use ref.watch when needed.

@TimWhiting
Copy link
Collaborator

Don't know if it is possible but could we still have a Computed that watches a provider but is also able to read from a ScopedProvider? A restriction could be that no other providers can depend on a Computed so it will be at the leaves of the graph.

@rrousselGit
Copy link
Owner Author

Don't know if it is possible but could we still have a Computed that watches a provider but is also able to read from a ScopedProvider? A restriction could be that no other providers can depend on a Computed so it will be at the leaves of the graph.

That's feasible, but why?

@TimWhiting
Copy link
Collaborator

Don't know if it is possible but could we still have a Computed that watches a provider but is also able to read from a ScopedProvider? A restriction could be that no other providers can depend on a Computed so it will be at the leaves of the graph.

That's feasible, but why?

So I can use the scoped provider as a key for a family provider and not have to obtain the key and then pass it in to the family. The Computed would get the relevant provider from the family using the ScopedProvider state as key.

@rrousselGit
Copy link
Owner Author

I will see later for this. It's far less important.

@rrousselGit
Copy link
Owner Author

Good thing haven't made an article about Riverpod yet, because that's going to be a big breaking change haha

With the fusion of Computed vs Provider, it also changes how providers are consuming a FutureProvider/...:

final streamProvider = StreamProvider((ref) async => 42);

final other = Provider((ref) {
  AsyncValue<int> a = ref.read(streamProvider);
  AsyncValue<int> b = ref.watch(streamProvider); // both read and watch returns the same thing

  Stream<int> c = ref.read(streamProvider.stream);
  Future<int> c = ref.read(streamProvider.last);

});

@rrousselGit
Copy link
Owner Author

I've got most of it working~
Now I'm focused on rewriting the tests, which is going to take quite some time.

I'd say this should be published (documentation included) within 2 weeks.

@rrousselGit
Copy link
Owner Author

rrousselGit commented Jul 30, 2020

Alright, I've published a dev release (0.6.0-dev)

It's lacking a changelog; ScopedProvider is not yet implemented, and https://riverpod.dev isn't updated yet.
But the dartdoc and examples are up-to-date

The compiler should help you migrate in most cases.

@rrousselGit rrousselGit changed the title Riverpod v2: ComputedFuture, ScopedProvider, and misc changes Riverpod v2: ref.watch, ScopedProvider, and misc changes Jul 30, 2020
@rrousselGit rrousselGit linked an issue Aug 2, 2020 that may be closed by this pull request
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
breaking enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add listener Widget Implement a "Retry" feature Explicit Dependency / Factories
5 participants