Code Monkey home page Code Monkey logo

riverpod's Introduction

Build Status codecov Star on Github License: MIT Discord

Deploys by Netlify

Riverpod


A reactive caching and data-binding framework. https://riverpod.dev
Riverpod makes working with asynchronous code a breeze by:

  • handling errors/loading states by default. No need to manually catch errors
  • natively supporting advanced scenarios, such as pull-to-refresh
  • separating the logic from your UI
  • ensuring your code is testable, scalable and reusable
riverpod pub package
flutter_riverpod pub package
hooks_riverpod pub package

Welcome to Riverpod (anagram of Provider)!

For learning how to use Riverpod, see its documentation:
>>> https://riverpod.dev <<<

Long story short:

  • Define network requests by writing a function annotated with @riverpod:

    @riverpod
    Future<String> boredSuggestion(BoredSuggestionRef ref) async {
      final response = await http.get(
        Uri.https('https://boredapi.com/api/activity'),
      );
      final json = jsonDecode(response.body);
      return json['activity']! as String;
    }
  • Listen to the network request in your UI and gracefully handle loading/error states.

    class Home extends ConsumerWidget {
      @override
      Widget build(BuildContext context, WidgetRef ref) {
        final boredSuggestion = ref.watch(boredSuggestionProvider);
        // Perform a switch-case on the result to handle loading/error states
        return boredSuggestion.when(
          loading: () => Text('loading'),
          error: (error, stackTrace) => Text('error: $error'),
          data: (data) => Text(data),
        );
      }
    }

Contributing

Contributions are welcome!

Here is a curated list of how you can help:

  • Report bugs and scenarios that are difficult to implement
  • Report parts of the documentation that are unclear
  • Fix typos/grammar mistakes
  • Update the documentation or add examples
  • Implement new features by making a pull-request

Sponsors

riverpod's People

Contributors

ahmedlsayed9 avatar alexhartford avatar aspiiire avatar bytes7bytes7 avatar chunghha avatar coyksdev avatar dependabot[bot] avatar freemansoft avatar giandifra avatar gitgud31 avatar jaichangpark avatar jpdesarrolloapp avatar julienlebren avatar k9i-0 avatar leonardorosaa avatar lucavenir avatar manavb2214 avatar marcoredz avatar minbyeongdon avatar mono0926 avatar papihack avatar rcjuancarlosuwu avatar robertbrunhage avatar rrousselgit avatar tbm98 avatar timwhiting avatar toshi-kuji avatar utamori avatar valentinvignal avatar yiss avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

riverpod's Issues

Allow optional minimum load time for AsyncValue.when

I love how concise and safe the behavior of AsyncValue is for handling success, loading, and error states. However, when loading only takes a split second, it looks a bit jumpy when going from the loading state to the success state.

I was wondering if having an optional parameter to the loading function allowing for a minimum time spent loading would be a good idea just so things don't appear as jittery once the data is loaded.

Prior to adopting Riverpod, I was using a FutureBuilder on my splash screen to force it to wait 2 seconds before displaying the app content. That doesn't quite work when the parent context is responsible for where the user is routed.

In this example, the splash screen is shown for around 100ms before being redirected to the Login or Home page:

return authProvider.when(
  data: (user) => user == null ? Login() : Nav(),
  loading: () => Splash(),
  error: (err, stack) => Center(child: Text('Error: $err')),
);

[question] How to get an initialized provider every time user open a page?

Question

Would you like to tell me how to dispose Provider when a page is popped, or any solution to get an initialized provider every time user open a page?

I knew Provider is disposed when its owner is disposed, and tried to prepare multi ProviderScopes and wrapped a destination page with it. but it’s not working.

@hwidget
Widget secondPageWithScope() {
  return ProviderScope(
    key: ValueKey('2nd Scope'),
    child: SecondPage(),
  );
}

Full code is here:
https://gist.github.com/HeavenOSK/74cb5eb0a3cc01d4d897198e15193986

[0.6.0-dev] `useProvider` triggers pointless rebuild when the value type is collection

Describe the bug

useProvider triggers pointless rebuild when the value is collection type.

To Reproduce

At 0.6.0-dev+2, executed this.
build log will be printed each time PRESS ME button is pressed.

import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';

void main() => runApp(const ProviderScope(child: App()));

class App extends StatelessWidget {
  const App({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: HomePage(),
    );
  }
}

class HomePage extends HookWidget {
  const HomePage({Key key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    print('build');
    useProvider(_stateProvider.select((value) => value.state));
    return Scaffold(
      appBar: AppBar(),
      body: RaisedButton(
        child: const Text('PRESS ME'),
        onPressed: () => context.read(_stateProvider).state = [42],
      ),
    );
  }
}

final _stateProvider = StateProvider((_) => [42]);

If [42](List<int>) is changed to 42(int), the problem doesn't occurs, so collection comparison seems broken.

Expected behavior

build should be printed at first time when the UI appeared, and shouldn't be printed when PRESS ME button pressed.
At 0.5.1, it works well without any problems.

Proposal: Include a debounced search to the Marvel example

Given that async operations are quite common, I think it would be helpful to add a simple search functionality to the Marvel example that would debounce the input query.
How do you approach such functionality, if possible, in a reusable way?

Sorry if this would fit better in the state_notifier or hooks package. I felt like asking because of the Marvel project 😄

Congratulations on all the packages @rrousselGit !

Explicit Dependency / Factories

Is your feature request related to a problem? Please describe.
Yes.
The problem is that I want to be able to debug a mobile multiplayer game application by having two copies of it side by side in a flutter desktop application.

Describe the solution you'd like
I want to be able to override one provider, and any provider that depends on it is also overridden. Essentially I want to give each instance of the application a unique id, and then use the same set of providers that depend on that unique ID but have the reference to them result in a different set of providers per unique ID.

Describe alternatives you've considered
Currently I override the unique ID provider for each subtree and also have to override all providers that depend on the unique ID. The issue with this is that it creates a lot of code bloat in the widget tree (at the place I'm overriding). It also makes it not compile-safe, since I can't know for sure if I've overridden all of the providers that I need to.

The ideal solution would be to just need to override the unique ID provider, and all providers that depend on it are automatically resolved to a different instance of the provider. (I understand why this is not the case, since some providers are meant to be singletons, rather than factories).

I was using this library as soon as I watched your youtube video introducing this. I'm so glad to see the progress and continued work on this! Back then there was no Computed or Families, which both seem to sort of address this problem.

However, using families mean everywhere I obtain a provider, I also have to obtain the unique ID provider to reference the provider I actually want.
I could solve this by using a Computed that computes the provider I want based on the unique ID provider. However, this means that for every provider I want duplicated I have to create a computed to go along with it. As well as in the documentation of computed it mentions that it might get called multiple times, even if the inputs haven't changed.

Additional context
Here is my provider dependency diagram.
Multiplayer ID is the unique ID that I've been talking about.
gamestate

Proposed Solution
I think I would propose an argument to the providers. uniqueForDependencies or keys, that would make them resolve to different providers if the set of uniqueForDependencies / keys are different. Similar to the keys argument of flutter_hooks.

i.e.

// Providers
final idProvider = Provider((_) => 1)
final storageProvider = Provider((ref) => StorageProvider(ref), uniqueForDependencies: [idProvider])

class StorageProvider {
  ProviderReference ref;
  Box box;
  StorageProvider(this.ref){
   init();
  }
  Future<void> init() async {
    box = Hive.box('${ref.read(idProvider).value}');
  }
  String get clientId => box.get('clientId');
}

// Widget tree
void main() => runApp(
ProviderScope(
  child: Row(
    children: [
      // App id == 1
      MyApp(), 
      ProviderScope(
        child: MyApp(),
        overrides: [
           // App id == 2
           // Overriding id Provider should also override storage provider for this subtree
           idProvider.overrideForSubtree(Provider((_) => 2))
         ],
      ),
    ],
  ),
));

class MyApp extends HookWidget {
  // Inside my app
  Widget build(BuildContext context){
    // This resolves to a different instance of storage provider per MyApp instance.
    final storage = useProvider(storageProvider);
    print(storage.clientId);
    // gets client id from one storage box within one MyApp instance
    // and a different client id from a different storage box within the other MyApp instance.
  } 
}

Expose `refresh(Provider)` to `Provider`s via `ProviderReference`

Is your feature request related to a problem? Please describe.
I'm working on an app that uses riverpod and I'm finding that it's annoying and limiting that the only place where I can mark a Provider as needing to be refreshed / triggering it to be refreshed is from within the widget tree. In other words, I have to be somewhere that has a BuildContext in scope so that I can do context.refresh(someProvider).

For context, I'm building an app for storing recipes. One of the things you can do is delete a recipe. I am managing the lifecycle of deleting a recipe with a StateNotifier called DeleteRecipeNotifier. The notifier is pretty trivial. It roughly looks like this:

class DeleteRecipeNotifier extends StateNotifier<AsyncValue<bool>> {
  final Api api;

  DeleteRecipeNotifier({@required this.api}) : super(AsyncValue.data(false));

  Future<void> deleteRecipe(String id) async {
    state = const AsyncValue.loading();
    state = await AsyncValue.guard(() async {
      await api.deleteRecipe(id);
      return true;
    });
  }
}

This is paired with some UI for showing a bottom sheet with a confirm button and a loading indicator while the delete is happening. When the delete is successful, the bottom sheet is closed and the UI pops back to a different screen.

(forgive me for blending hooks and non-hooks here 😄 i'm exploring some different approaches)

class _DeleteSheet extends HookWidget {
  final Recipe recipe;

  const _DeleteSheet({
    Key key,
    @required this.recipe,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ProviderListener(
      onChange: (AsyncValue<bool> result) {
        if (result.data?.value ?? false) {
          context.refresh(recipesProvider);
          // close the bottom sheet and also pop back out of the current "view recipe screen"
          Nav.of(context)..pop()..pop();
        }
      },
      provider: deleteRecipeProvider.state,
      child: useProvider(deleteRecipeProvider.state).when(
        data: (_) => _ConfirmDelete(recipe: recipe),
        loading: () => Center(child: CircularProgressIndicator()),
        error: (e, __) => Center(child: Text(e.toString())),
      ),
    );
  }
}

Describe the solution you'd like
What I'd love to be able to do is trigger a refresh of the recipesProvider from within my DeleteRecipeNotifier. Either by constructing it with a ProviderReference or passing in a lambda like refreshRecipes: () => ref.refresh(recipesProvider) to keep ProviderReference out of the notifier.

Describe alternatives you've considered
Alternatively, I can keep doing what I'm doing in the example code above: listen to the notifier and trigger a refresh from the widget tree. If you've got a strong reason why I should prefer this approach, I'd love to hear more! I'm sure you have a philosophy around how this stuff should be done. I'm open to all sorts of ideas, and I totally accept that I might be thinking about this wrong.

Thanks!

In `flutter_riverpod: ^0.6.0-dev+3` i can't use the computed?

Im using flutter_riverpod: ^0.6.0-dev+3 in my project, and i can't find the computed method !

in flutter_riverpod: ^0.5.1 i can find the computed method but in dev i could not find even if i use flutter LSP throws me an error

why is that? please help me if i'm wrong!

Provider a way to merge AsyncValue together

Is your feature request related to a problem? Please describe.
I'm refactoring a small app I have to use river_pods but one thing I keep wanting is a way to combine providers in a when or maybeWhen so they both get loaded at the same time in the case they're asynchronous.

Describe the solution you'd like

// Both userProvider and profileProvider are `StreamProvider`s
return useProvider2(userProvider, profileProvider).when(
  data: (user, profile) {
    // Logged in
  },
  loading: () {},
  error: (_, __) {}
);

Or, another example, all possible badges (pulled from a json file) and the user's current badges.

// userBadgesProvider is a StreamProvider and badgesProvider is a FutureProvider
return useProvider2(userBadgesProvider, badgesProvider).when(
  data: (userBadges, allBadges) {
    // Show list of a user's current badges in list of all possible badges
  },
  loading: () {},
  error: (_, __) {}
);

Describe alternatives you've considered
I can do what I want by checking both the .data values on the providers to check if they're null but then I lose out on the error case of when:

final user = useProvider(userProvider).data;
final profile = useProvider(profileProvider).data;
final isLoggedIn = user != null && profile != null;

Or for the other example, I currently do this:

useProvider(userBadgesProvider).when(
  data: (userBadges) {
    final badges = useProvider(badgesProvider).maybeMap<List<Badge>>(
      data: (asyncData) => asyncData.data.value,
      orElse: () => [],
    );
  },
  loading: () {},
  error: (_, __) {},
),

Additional context
hooks_riverpod: 0.6.0-dev

[✓] Flutter (Channel dev, 1.21.0-1.0.pre, on Mac OS X 10.15.5 19F101, locale en-US)
 
[✓] Android toolchain - develop for Android devices (Android SDK version 29.0.3)
[✓] Xcode - develop for iOS and macOS (Xcode 11.6)
[✓] Chrome - develop for the web
[✓] Android Studio (version 3.6)
[✓] Connected device (3 available)

example for StreamProvider

I would like to see a more detailed example with StreamProvider in the docs. I think in the flutter / firebase context, a really nice example would be the equivalent of this from the provider way of things:

StreamProvider<FirebaseUser>.value(
            value: FirebaseAuth.instance.onAuthStateChanged);

translated to River Pod, it might look like this, but i could be wrong (since i am trying to clean up here, its not 1:1 translation as is):

final firebaseAuthProvider = StreamProvider<FirebaseUser>((ref) {
  ref.onDispose(() {
    // Closes the StreamController when the state of this provider is destroyed.
    FirebaseAuth.instance.signOut();
  });

  return FirebaseAuth.instance.onAuthStateChanged;
});

Please correct me if i am wrong on this.

ChangeNotifierProvider clarification

I was reading the ChangeNotifierProvider documentation and I found out the following note:

Note: By using Riverpod, ChangeNotifier will no-longer be O(N^2) for dispatching notifications and O(N) for adding/removing listeners.

Could you maybe specify something more about that statement? Is it better by using Riverpod, worse, or?

Where should I put Computed?

As far as I know, Computed is like a filter and it only calculates and notifies Consumer when there's a change. So in case I have a complex state, I need a lot of Computed, should I set my Computed as global variables or set it as static variables or something else?
If I set as global variables, I can't remember them all 😕

Initialize StateNotifierProvider with async data

Describe what scenario you think is uncovered by the existing examples/articles

There is a simple use case. I want to create a todoList stateNotifierProvider that is initialized with todos fetched from API. If I fetch the todos on a initialize function inside the stateNotifier class I can't get the states of an asyncValue from a futureProvider (loading, error and data).

Describe why existing examples/articles do not cover this case

There aren't examples covering this type of cases where stateNotifierProviders are needed, to create a state and some logic to change this state, but getting the benefits of an asyncValue states returned by a futureProvider.

StateNotifierProvider.family.autoDispose causes grey screen on Flutter Web (Release build)

Describe the bug

I am not sure this is a Flutter bug or Riverpod bug.

When using StateNotifierProvider.family.autoDispose, it causes a grey screen on Flutter Web. Only happens on Release build, Debug is fine. If I don't use autoDispose it is also fine. I think I didn't experience this before the family.autoDispose style new syntax. My current work-around is not to use autoDispose.

I get this on the web console:
Another exception was thrown: Instance of 'minified:iu<void>'

Possibly related:

  1. flutter web : Another exception was thrown: Instance of 'minified:aM'
  2. How to fix the “minified:aq” flutter web error

In my case, it was an static method uninitialized unexpectedly that triggered this issue. Seems like a webdev bug , only failed on web release build.

To Reproduce

  1. use StateNotifierProvider.family.autoDispose
  2. build with flutter web release mode

Regards

Using:

Flutter 1.21.0-1.0.pre • channel dev • https://github.com/flutter/flutter.git
Framework • revision f25bd9c55c (3 weeks ago) • 2020-07-14 20:26:01 -0400
Engine • revision 99c2b3a245
Tools • Dart 2.9.0 (build 2.9.0-21.0.dev 20bf2fcf56)

Unwanted State Rebuilds

Describe the bug
Riverpod Version -> 0.6.0-dev+3

Context
The task is to listen to two Providers namely FirebaseAuthProvider and a PageControllerProvider., use the data to determine: continue being in the IntroFlow or show the HomePage.

Snippet for the Provider:
https://github.com/preetjdp/YouOweMe/blob/5e51fb2f6132e637ad447273419f4360a27ad1d4/mobileApp/lib/ui/IntroFlow/providers.dart#L18-L45

The Problem
When the user sign's in, i.e., the FirebaseUserProvider returns a new value the widget where the data is being used gets rebuild.,

The Snippet where the provider is used:
https://github.com/preetjdp/YouOweMe/blob/5e51fb2f6132e637ad447273419f4360a27ad1d4/mobileApp/lib/ui/IntroFlow/introFlow.dart#L22-L45

My Hypothesis
I believe the provider gets reset since I see the loading widget on the screen.

Example

[0.6.0-dev] marvel example app is broken at `ProviderScope(overrides:)`

Describe the bug

As you described this, I tried to use 0.6.0-dev, but marvel example app is broken at ProviderScope(overrides:).

But the dartdoc and examples are up-to-date
#49 (comment)

The app doesn't work and error occurs.

Error log:

══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
The following UnsupportedError was thrown building NotificationListener<KeepAliveNotification>:
Unsupported operation: Cannot override providers on a non-root ProviderContainer/ProviderScope

When the exception was thrown, this was the stack:
#0      new ProviderContainer (package:riverpod/src/framework/container.dart:51:7)
#1      ProviderScopeState.initState (package:flutter_riverpod/src/framework.dart:166:17)
#2      StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:4695:58)
#3      ComponentElement.mount (package:flutter/src/widgets/framework.dart:4531:5)
...     Normal element mounting (33 frames)
#36     Element.inflateWidget (package:flutter/src/widgets/framework.dart:3501:14)
#37     Element.updateChild (package:flutter/src/widgets/framework.dart:3260:18)
#38     SliverMultiBoxAdaptorElement.updateChild (package:flutter/src/widgets/sliver.dart:1157:36)
#39     SliverMultiBoxAdaptorElement.createChild.<anonymous closure> (package:flutter/src/widgets/sliver.dart:1142:20)
#40     BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2620:19)
#41     SliverMultiBoxAdaptorElement.createChild (package:flutter/src/widgets/sliver.dart:1135:11)
#42     RenderSliverMultiBoxAdaptor._createOrObtainChild.<anonymous closure> (package:flutter/src/rendering/sliver_multi_box_adaptor.dart:356:23)
#43     RenderObject.invokeLayoutCallback.<anonymous closure> (package:flutter/src/rendering/object.dart:1879:58)
#44     PipelineOwner._enableMutationsToDirtySubtrees (package:flutter/src/rendering/object.dart:927:15)
#45     RenderObject.invokeLayoutCallback (package:flutter/src/rendering/object.dart:1879:13)
#46     RenderSliverMultiBoxAdaptor._createOrObtainChild (package:flutter/src/rendering/sliver_multi_box_adaptor.dart:345:5)
#47     RenderSliverMultiBoxAdaptor.addInitialChild (package:flutter/src/rendering/sliver_multi_box_adaptor.dart:429:5)
#48     RenderSliverGrid.performLayout (package:flutter/src/rendering/sliver_grid.dart:550:12)
#49     RenderObject.layout (package:flutter/src/rendering/object.dart:1776:7)
#50     RenderSliverEdgeInsetsPadding.performLayout (package:flutter/src/rendering/sliver_padding.dart:137:11)
#51     RenderSliverPadding.performLayout (package:flutter/src/rendering/sliver_padding.dart:377:11)
#52     RenderObject.layout (package:flutter/src/rendering/object.dart:1776:7)
#53     RenderViewportBase.layoutChildSequence (package:flutter/src/rendering/viewport.dart:471:13)
#54     RenderViewport._attemptLayout (package:flutter/src/rendering/viewport.dart:1465:12)
#55     RenderViewport.performLayout (package:flutter/src/rendering/viewport.dart:1374:20)
#56     RenderObject.layout (package:flutter/src/rendering/object.dart:1776:7)
#57     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:13)
#58     RenderObject.layout (package:flutter/src/rendering/object.dart:1776:7)
#59     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:13)
#60     RenderObject.layout (package:flutter/src/rendering/object.dart:1776:7)
#61     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:13)
#62     RenderObject.layout (package:flutter/src/rendering/object.dart:1776:7)
#63     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:13)
#64     RenderObject.layout (package:flutter/src/rendering/object.dart:1776:7)
#65     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:13)
#66     RenderObject.layout (package:flutter/src/rendering/object.dart:1776:7)
#67     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:13)
#68     RenderObject.layout (package:flutter/src/rendering/object.dart:1776:7)
#69     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:13)
#70     RenderObject.layout (package:flutter/src/rendering/object.dart:1776:7)
#71     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:13)
#72     RenderObject.layout (package:flutter/src/rendering/object.dart:1776:7)
#73     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:13)
#74     RenderObject.layout (package:flutter/src/rendering/object.dart:1776:7)
#75     MultiChildLayoutDelegate.layoutChild (package:flutter/src/rendering/custom_layout.dart:173:11)
#76     _ScaffoldLayout.performLayout (package:flutter/src/material/scaffold.dart:497:7)
#77     MultiChildLayoutDelegate._callPerformLayout (package:flutter/src/rendering/custom_layout.dart:242:7)
#78     RenderCustomMultiChildLayoutBox.performLayout (package:flutter/src/rendering/custom_layout.dart:401:14)
#79     RenderObject.layout (package:flutter/src/rendering/object.dart:1776:7)
#80     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:13)
#81     RenderObject.layout (package:flutter/src/rendering/object.dart:1776:7)
#82     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:13)
#83     _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1269:11)
#84     RenderObject.layout (package:flutter/src/rendering/object.dart:1776:7)
#85     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:13)
#86     RenderObject._layoutWithoutResize (package:flutter/src/rendering/object.dart:1639:7)
#87     PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:896:18)
#88     RendererBinding.drawFrame (package:flutter/src/rendering/binding.dart:404:19)
#89     WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:881:13)
#90     RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:286:5)
#91     SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1117:15)
#92     SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1056:9)
#93     SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:972:5)
#97     _invoke (dart:ui/hooks.dart:253:10)
#98     _drawFrame (dart:ui/hooks.dart:211:3)
(elided 3 frames from dart:async)

To Reproduce

At https://github.com/rrousselGit/river_pod/tree/v0.6.0-dev, runexamples/marvel/lib/main.dart.

Expected behavior

The app works without any errors.

StateNotifier is missing from package ?

Describe the bug
Trying to import StateNotifier from flutter_riverpod.dart

To Reproduce

import 'package:flutter_riverpod/flutter_riverpod.dart';
class Counter extends StateNotifier<int> {
	Counter(): super(0);
}

seems like the riverpod has not included the StateNotifier, do we need to install this package on our own from state_notifier?
thanks

The member 'state' can only be used within instance members of subclasses of 'package:state_notifier/state_notifier.dart'

I follow source code from documentation :

Documentation example

class Counter extends StateNotifier<int> {
  Counter(): super(0);

  void increment() => state++;
}

final counterProvider = StateNotifierProvider((ref) => Counter());

// ...

@override
Widget build(BuildContext context) {
  // Obtains Counter without listening to its state.
  // Will not cause the button to rebuild when the counter changes.
  final Counter counter = useProvider(counterProvider);

  return RaisedButton(
    onPressed: () => counter.increment(),
    child: Text('increment'),
  );
}

Then i want custom it , when i click button i want show circularprogressindicator , after 3 second showing the text. So i already custom the example documentation to this :

ProviderLoading.dart

import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:state_notifier/state_notifier.dart';

class IsLoading extends StateNotifier<bool> {
  IsLoading() : super(false);
  void toggleLoading(bool value) => state = value;
}

final isLoadingProvider = StateNotifierProvider((ref) => IsLoading());

Main.dart


class TestingApp extends HookWidget {
  @override
  Widget build(BuildContext context) {
    final IsLoading isLoading = useProvider(isLoadingProvider);
    return Scaffold(
      body: Container(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Center(
              child: isLoading.state ? CircularProgressIndicator() : Text('This Is Your Data'),
            ),
            Padding(
              padding: const EdgeInsets.all(8.0),
              child: FlatButton(
                  onPressed: () => showLoading(isLoading), child: Text('Toggle Loading')),
            ),
          ],
        ),
      ),
    );
  }

  void showLoading(IsLoading isLoading) async {
    isLoading.toggleLoading(true);
    print("Proses");
    await Future.delayed(const Duration(seconds: 3));
    print("Done");
    isLoading.toggleLoading(false);
  }
}

But i got this warning and although i click button , it not showing the circularprogressindicator:

The member 'state' can only be used within instance members of subclasses of 'package:state_notifier/state_notifier.dart'.dart(invalid_use_of_protected_member)

I missed something ?

ProviderListener missing events

my code:

import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';

import 'events/event_base.dart';
import 'events/loading_event.dart';
import 'events/show_snackbar_event.dart';

final eventProvider = StateProvider<EventBase>((ref) => null);

void main() {
  runApp(ProviderScope(child: MyApp()));
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulHookWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  void onChange(StateController<EventBase> event) {
    print(event.state);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
        ),
        body: ProviderListener(
          provider: eventProvider,
          onChange: onChange,
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[],
          ),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () {
            context.read(eventProvider).state = LoadingEvent();
            context.read(eventProvider).state = ShowSnackbarEvent();
          },
          tooltip: 'Increment',
          child: Icon(Icons.add),
        ));
  }
}

Expected:

flutter: Instance of 'LoadingEvent'
flutter: Instance of 'ShowSnackbarEvent'

actually

flutter: Instance of 'ShowSnackbarEvent'

LoadingEvent is skiped.

Document overrides and overridesas

You probably already have this on your todo list, but I think documenting these, especially for how to use them for unit tests would be very good to have, as all of the tests in the examples so far don't seem to make use of this.

Add listener Widget

Is your feature request related to a problem? Please describe.
I want to pass event from provider to widget
issue related: #21

Describe the solution you'd like
Create a widget like BlocListener.
It can pass events to widget then I can do something like navigation, showDialog ......

Current solution
Create a Stream in Provider and listen it in StatefulWidget or Hooks widget.

How can I use ChangeNotifierProvider/StateNotifierProvider with Consumer

The doc only has an example for flutter_hooks useProvider. But I only want to use flutter_riverpod's Consumer only.

I tried this but the view is not updated when the data is changed:

class SomeState with ChangeNotifier {
   String data = '';

  void getData() async {
    data = 'abc';
    notifyListeners();
  }
}

final stateProvider = ChangeNotifierProvider<SomeState>((_) => SomeState());


// ...

stateProvider.read(context).getData();

// ...

return Consumer((_, read) {
  final state = read(stateProvider);

  return Text(state.data);
})

Request for comments: Should all providers be merged into one?

Hello and thanks for reading!

This issue is about slightly changing the syntax of how provider variants are created.
Feel free to comment and share your opinion on the matter!

The problem

Currently, we have many classes, which are all basically the same modulo a small name + prototype change.

The current syntax is a permutation of:

State Provider
AutoDispose ChangeNotifier Family
Future
Stream
StateNotifier

For a total of 24 variants.

With a secondary table for Computed.

But that's not very ideal:

  • It leads to ridiculously long names, such as AutoDisposeChangeNotifierProviderFamily
  • It pollutes the auto-complete with tons of classes named almost the same
  • Adding new permutations increase the number of providers exponentially

The last point is especially important, as ideally, I would like to add new variants:

  • A "Retry" variant, for well, having states that can be retried
  • Extract Future/Stream in a separate column, such that we could have a FutureStateProvider for example

Which means the table of variants would become:

Provider _
AutoDispose Retry Future StateNotifier Family
Stream State
ChangeNotifier

That leads to a ridiculous 128 providers

The Solution

The idea is to merge all the variants into two public classes: Provider and Computed.
Riverpod would still have 128 providers internally, but they would be code-generated so it doesn't matter for end-users.

The way this new syntax would work is using the Builder design pattern.

Basically, instead of:

final provider = AutoDisposeChangeNotifierProviderFamily<MyNotifier, int>((ref, id) {
  return MyNotifier();
});

We would have:

final provider = Provider
    .changeNotifier
    .autoDispose
    .family<MyNotifier, int>((ref, id) {
  return MyNotifier();
});

Whereas:

final provider = AutoDisposeProvider<Object>((ref) => Object());

would become:

final provider = Provider.autoDispose<Object>((ref) => Object());

And Provider((ref) => Object()) would be untouched.

The difference:

  • Only a single public class. We are not polluting the auto-complete anymore (the 128 variants would still be public but in a different import like package:riverpod/providers.dart)
  • More intuitive. Newcomers will have an easier time discovering all the possibilities
  • A more logical documentation. Instead of documenting "AutoDisposeStreamProvider", we can individually document the .stream and .autoDispose.

Questions

Should some provider variants stay as is, such that we would still have StateProvider(...) instead of Provider.state(...)?

If so, what are the providers that we want to keep this way? I'm thinking of:

  • Provider
  • ChangeNotifierProvider
  • FutureProvider
  • StreamProvider
  • StateProvider
  • StateNotifierProvider

And then for fancier versions like FutureStateNotifierProvider would become StateNotifierProvider.future.

Documentation on the best way to nest providers inside other providers

Describe what scenario you think is uncovered by the existing examples/articles
Sometimes you want to nest providers inside of other providers for e.g. a listenable list where you want to only listen to item reordering, adding and removing, while all the internal items are individually listenable, so that you can avoid rebuilding everything when only a single item changes. What would be the most idiomatic way of achieving this in Riverpod?

How to use with MobX

Thank you very much for another great package. Is it possible to use Riverpod as a complete replacement for Provider to use in combination with MobX? Can it solve store-to-store communication problem? Any example or documentation?

Stack Overflow when use Consumer in dialog

  Future<void> _showDialogAddGhiChu(BuildContext context) async {
    return showDialog<void>(
      context: context,
      barrierDismissible: false, // user must tap button!
      builder: (_) {
        return Consumer((ct, read) {
          final clickDate = read(mainStateNotifier).clickDate;
          return AddNote(
            date: clickDate,
            context: ct,
          ); //magic ^_^
        });
      },
    );
  }

error

Another exception was thrown: Stack Overflow

════════ Exception caught by widgets library ═══════════════════════════════════════════════════════
The following StackOverflowError was thrown building Consumer(dirty, dependencies: [ProviderStateOwnerScope], state: _ConsumerState#34eeb):
Stack Overflow

The relevant error-causing widget was: 
  Consumer file:///Users/tbm98/dev/flutter_app/student-social/lib/presentation/screens/main/main_page.dart:132:16
When the exception was thrown, this was the stack: 
#0      MainState.getClickDate (package:studentsocial/presentation/screens/main/main_state.dart:35:3)
#1      MainState.getClickDate (package:studentsocial/presentation/screens/main/main_state.dart:35:32)
#2      MainState.getClickDate (package:studentsocial/presentation/screens/main/main_state.dart:35:32)
#3      MainState.getClickDate (package:studentsocial/presentation/screens/main/main_state.dart:35:32)
#4      MainState.getClickDate (package:studentsocial/presentation/screens/main/main_state.dart:35:32)
...
════════════════════════════════════════════════════════════════════════════════════════════════════

Instance of 'CircularDependencyError'

I got Instance of 'CircularDependencyError' but I don't know the reason for this error.
I have 2 providers that use each other

final calendarStateNotifier = StateNotifierProvider((ref) {
  return CalendarStateNotifier(
      ref.read(scheduleStateNotifier).value, ref.read(mainStateNotifier).value);
});

and

final scheduleStateNotifier = StateNotifierProvider((ref) {
  return ScheduleStateNotifier(ref.read(calendarStateNotifier).value);
});

Implement a "Retry" feature

A common use-case in modern applications is a "retry" feature – either refresh a feed or some request failed.
Thanks to providers being declarative, it is possible to have built-in support for such feature.

First, this would require #39 to make the syntax reasonable.

This would consist of the following things:

  • A MyProvider.retry((ref) {...}) modifier, to mark a state as retryable.
    This would wrap the exposed object in a Retry<T>.

    For example, if we have:

    final provider = FutureProvider((ref) async => 42);
    
    Widget build(context) {
      AsyncValue<int> value = useProvider(provider);
    }

    Then using the .retry modifier, we would have:

    final provider = FutureProvider.retry((ref) async => 42);
    
    Widget build(context) {
      Retry<AsyncValue<int>> value = useProvider(provider);
    }

    Where Retry is:

    abstract class Retry<T> {
      T get value.
      Future<T> retry();
    }
  • The .retry modifier would be specific to Future & StreamProvider only

  • The UI can then freely call Retry.retry(), which would destroy the previous state and re-create a new state for the given provider.

  • The result of Retry.retry is a Future<T> that resolves when the state is re-created

  • The constructor of a .retry provider would expose an parameter to define what state should be displayed during the AsyncValue.data to AsyncValue.data transition:

    • show the previous value
    • reset to AsyncValue.loading

    This parameter could be named gaplessPlayback, which is the named used by the Image widget for the same behavior.
    We could also have an enum.

  • A provider marked with .rety can hook-up on the retry event to perform some clean-up using ref:

    final provider = FutureProvider.retry((ref) async {
     ref.onRetry(() {
       // TODO: clear cache, so that the next request doesn't simply return the same result.
     });
    
     return 42;
    });
  • When using ref.read(futureProvider), the value obtained is always a Stream<T>, even for FutureProvider.retry – as the value exposed by a retryable FutureProvider can change over time.

Usage example

All in all a typical usage would be a FutureProvider that performs an HTTP request.
Then, the UI would expose a way for users to restart the request, such as with a pull-to-refresh or a "retry" button.

In code, this would look like this:

class Todos {
  static final provider = FutureProvider.retry(
    (ref) async {
      final repository = ref.read(Repository.provider);
      return repository.fetchTodos();
    },
    // during retry, keep showing the previous state
    gaplessPlayback: true,
  );
}

...

Widget build(context) {
  final todos = useProvider(User.provider);

  return todos.value.when(
    loading: () => const CircularProgressIndicator(),
    error: (err, stack) {
      return Column(
        children: [
          Text('Error $err'),
          RaisedButton(
            onPressed: () => user.retry(),
            child: Text('retry'),
          ),
        ],
      );
    },
    data: (todos) {
      return RefreshIndicator(
        onRefresh: () => user.retry(),
        child: ListView(
          children: [
            for (final todo in todos) TodoItem(todo: todo),
          ],
        ),
      );
    },
  );
}

[Question] ProviderReference removed in ProviderContainer

I was taking a look at the progress in the new branch merge_computed_and_provider and I noticed that the commit 0431576 has removed the getter for the ProviderReference in the ProviderContainer class, breaking the Marvel example test in the process, which was doing the following:

final container = ProviderContainer();
final client = FakeDio();
final repository = MarvelRepository(container.ref, client: client);

I was wondering what would be the new way of doing this inside the tests now.
I'm sure you are planning to update/fix the examples, but I was just curious 😅

ProviderScope override "forgets" the StreamProvider value during navigation

Describe the bug
When creating a StreamProvider with a value of Stream.value(null) and then override it in another page then this should only be null until it is set. Right now it seems like it resets when navigating with an animation.

Have added a deugPrint(user.name) to easily see the behavior in the console.

To Reproduce
Click the ListTile and look at the log.

class User {
  String id;
  String name;

  User.empty() {
    id = "";
    name = "";
  }

  User.other() {
    id = "12345";
    name = "Tester";
  }

  @override
  bool operator ==(Object other) => identical(this, other) || other is User && runtimeType == other.runtimeType && name == other.name;

  @override
  int get hashCode => name.hashCode;
}

final userProvider = StreamProvider<User>((ref) {
  return Stream.value(User.empty());
});
void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ProviderScope(
      child: MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
          primarySwatch: Colors.blue,
          visualDensity: VisualDensity.adaptivePlatformDensity,
        ),
        home: PageOne(),
      ),
    );
  }
}

class PageOne extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ProviderScope(
      // This override is causing the issue.
      // If this override would be at the material app
      // then the debugPrint will always print Tester
      overrides: [
        userProvider.overrideAs(
          StreamProvider(
            (ref) => Stream.value(User.other()),
          ),
        ),
      ],
      child: Scaffold(
        body: OpenContainer(
          closedElevation: 4,
          closedBuilder: (BuildContext context, VoidCallback openContainer) {
            return Consumer((context, read) {
              final user = read(userProvider).data == null ? User.empty() : read(userProvider).data.value;
              debugPrint(user.name);
              return Container(
                height: 100,
                child: ListTile(
                  title: Text(user.name),
                ),
              );
            });
          },
          openBuilder: (context, __) {
            return Scaffold();
          },
        ),
      ),
    );
  }
}

Do not forget to add dependencies in .yaml

  animations: ^1.1.0
  flutter_riverpod: ^0.1.0

Expected behavior
When running this the debugPrint(user.name) should not be empty during navigation.

provider to riverpod with param

Firstly, thanks a thousand times fot these great packages.

I wanted to move my entire project from provider to riverpod. But i’m stuck at this point.

class EditQuestionScreen extends StatelessWidget {
  EditQuestionScreen({this.question, this.answers});

  final QuestionModel question;
  final List<AnswerModel> answers;

  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
        create: (context) => QuestionProvider(
            question: this.question,
            answers: this.answers),
        child: Container());
  }
}

This is my provider widget for subwidgets. Its initialize only once. How can I move this class to Hook Widget with riverpod?

conditional provider like with Provider Package

Is your feature request related to a problem? Please describe.

I cant find a way to add a provider based on the value of a stream (in this case, the value of a firebase auth).

Describe the solution you'd like

Take this from provider package. This widgets sits on top of MaterialApp and get a builder which in fact is the whole app. So its a way to "inject" providers (here a firestore db provider with a valid connection based on user credentials) after a successful login.

class AuthWidgetBuilder extends StatelessWidget {
  const AuthWidgetBuilder({Key key, @required this.builder}) : super(key: key);
  final Widget Function(BuildContext, AsyncSnapshot<User>) builder;

  @override
  Widget build(BuildContext context) {
    final authService = Provider.of<AuthService>(context, listen: false);
    return StreamBuilder<User>(
      stream: authService.onAuthStateChanged,
      builder: (BuildContext context, AsyncSnapshot<User> snapshot) {
        final User user = snapshot.data;
        if (user != null) {
          return MultiProvider(
            providers: <SingleChildCloneableWidget>[
              Provider<User>.value(value: user),
              ProxyProvider<User, FirestoreDatabase>(
                update: (_, User user, __) => FirestoreDatabase(uid: user.uid),
              )
            ],
            child: builder(context, snapshot),
          );
        }
        return builder(context, snapshot);
      },
    );
  }
}

Additional context

I think "emulating" ProxyProvider in Riverpod should be quite easy with the "ref" variable but the whole concept of conditional providers is not clear. Perhaps i am missing something very basic here.

It's possible to only update needed property ?

In todos example , to only update property completed we should defined another property again . It's possible to only updated only needed property ? something like this :

 state = [
      for (final todo in state)
        if (todo.id == id)
          Todo(
            completed: !todo.completed,
          )
        else
          todo,
    ];

already try this approach,but make property another completed null. Is this really the way it works?

Because i have alot of property and only need update 1 of them. But i should defined another property again.

My example

state = [
      for (final item in state)
        if (item.idUtang == idUtang)
          UtangModel(
            idUtang: item.idUtang,
            pembertang: item.pembertang,
            pengutang: item.pengutang,
            totalUtang: item.totalUtang,
            sisaUtang: item.sisaUtang,
            status: '1',
            keterangan: item.keterangan,
            tglKembali: item.tglKembali,
            selfie: item.selfie,
            createdDate: item.createdDate,
            ttd: item.ttd,
          )
        else
          item
    ];

Thank's.

Example of reflecting state updates across screens

The todos example shows adding and dismissing todos on a single screen. It is quite clear how the state of the todo list is manipulated in this example.

Suppose however that the main todo list screen only shows todos coming up in the next week. The state notifier TodoList only loads this subset of todos from the data source for performance reasons.

Suppose further that the user can push another screen on to the navigation stack to show a different list of todos where there might be some overlap with the first list – some of those todos might be in the main screen's TodoList, some might not. This presumably requires another TodoList state notifier instance which loads that second set of todos.

The question arises of how to update state on the first screen when a todo is changed on the second screen. The second screen's TodoList state notifier will update its state and thus reflect the state change on the second screen.

What would be the best practise to propagate this state change to the TodoList's of both screens? Or is this thinking about it the wrong way and that you would instead have a single TodoList that changes its internal list according to the screen navigation?

I appreciate that this question relates more to state notifiers than provider, but I thought to pose it here as StateNotifier seems an important part of Riverpod.

[Bug] About dependencies

Describe the bug

it is happened.

Running "flutter pub upgrade" in my_app...                      

Because hooks_riverpod >=0.1.0 depends on flutter_hooks ^0.10.0 and my_app depends on flutter_hooks ^0.11.0, hooks_riverpod >=0.1.0 is forbidden.
So, because my_app depends on hooks_riverpod ^0.3.0, version solving failed.
pub upgrade failed (1; So, because my_app depends on hooks_riverpod ^0.3.0, version solving failed.)

To Reproduce

Modify pubspec.yaml below and excute flutter pub upgrade.

environment:
  sdk: ">=2.7.0 <3.0.0"
  flutter: ">= 1.17.0"

dependencies:
  flutter:
    sdk: flutter

  flutter_hooks: ^0.11.0
  hooks_riverpod: ^0.3.0

<Please add a small sample to that can be executed to reproduce the problem. As a general rule, 100 lines is the maximum>

it is about yaml. So, no code.

Expected behavior

downgrade flutter_hooks works, but it opponents for document.

  # flutter_hooks: ^0.11.0
  flutter_hooks: ^0.10.0
  hooks_riverpod: ^0.3.0

Consumer rebuilds entire widget tree

This is more of a question than an actual bug report. I'm trying to do the counter example using flutter_hooks, but I have noticed that when using hooks and consumer, when the state changes the entire widget tree is rebuilt.

class MyHomePage extends HookWidget {
  @override
  Widget build(BuildContext context) {
    final count = useProvider(counterProvider).state;
    debugPrint("Rebuild");
    return Scaffold(
      appBar: AppBar(
        title: Text("Counter Example"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Consumer((context, read) => Text(
                  "$count",
                  style: Theme.of(context).textTheme.headline4,
                )),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () => counterProvider.read(context).state++,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ), 
    );
  }
}

When I used Consumer from the provider package, it used to rebuild only the consumer widget. Is this a bug or am I missing something to make this work?

Error using useProvider with FamilyProvider

In my case it is a StateNotifierProviderFamily.

In a HookWidget, using the following line:
useProvider(mySNP(param).state);

I receive this error message AFTER changing the param:
Unsupported operation: Used `useProvider(provider)` with a `provider` different than it was before

Is object instantiation with Reader reference preferred over constructor injection?

Using the read method inside of a provider body is discouraged according to the docs, but the reason for this is unclear to me.

Is there a discernible difference in behavior between the following snippets?

final myServiceProvider = Provider((ref.read) => MyService(ref.read));


//initialization within constructor
MyService(Reader read)
: api=read(apiProvider);
final myServiceProvider = Provider(
    (ref) => MyService(api: ref.read(apiProvider)));

I don't have as much of an issue with passing the reader given that riverpod is compile safe, but constructor injection does have the advantage of making dependencies more explicit. Is this indeed an anti-pattern and if so why?

Allow some circular dependencies?

Is your feature request related to a problem? Please describe.

Given data classes of Post and Comment, Riverpod works great wiring up their repositories' "boot" dependencies (a tree-like structure):

hiveProvider <- postsHiveBoxProvider <- postsRepositoryProvider

hiveProvider <- commentsHiveBoxProvider <- commentsRepositoryProvider

Posts, Comments and other models, however, depend on each other. These relationships are better represented with a directed graph data structure, which can be navigated like:

final post = await ref.read(postsRepositoryProvider).getPost();
post.comments.first.post.value.comments.first...

Since postsRepository needs to hold a reference to commentsRepository, once ref.read(commentsRepositoryProvider) is called I get a CircularDependencyError.

Describe the solution you'd like

Allow disabling the circular reference assertion for legitimate cases like Providers in graph-like structures.

ref.read(commentsRepositoryProvider, circular: true)

Perhaps there are alternatives (using cached providers)? I not too familiar with Riverpod

Read original `Provider` from `Override`

Is your feature request related to a problem? Please describe.
Not sure if it should be a bug or a feature request, but I can't read the original Provider from Override.

For example:

final nameProvider = Provider<String>((ref) => 'John Doe');

final emphasisProvider = Provider<String>((ref) {
  final name = ref.read(nameProvider).value;
  return '$name!';
});

// ...

ProviderScope(
  child: Column(
    children: <Widget>[
      // Displays `John Doe`
      Consumer((context, read) => Text(read(nameProvider))),
      // Displays `John Doe!`
      Consumer((context, read) => Text(read(emphasisProvider))),
      ProviderScope(
        overrides: [
          nameProvider.overrideAs(emphasisProvider),
        ],
        // Displays `null!` instead of `John Doe!`
        child: Consumer((context, read) => Text(read(nameProvider))),
      ),
    ],
  ),
)

Describe the solution you'd like
Read original Provider value instead of returning null.

How to implement filter/search in state ?

I have simple example to search/ filter data in state , my type data state is List [UtangModel]. I can filtered list depending of what user type.

The problem is , although i success filtered the data but i lost data not what i type and it can't restore again. How best practice to implement search using state ?

Problem

Filter code

    void filterList(String query) {
    var fullList = [...state];
    var tempList = [];
    if (query.isEmpty) {
      tempList = [];
    } else {
      for (final item in fullList) {
        if (item.pengutang.nameUser.toLowerCase().contains(query.toLowerCase())) {
          tempList.add(item);
        }
      }
    }

    state = [...tempList];
    print('Total Filtered list ${fullList.length}');
  }

It's how i call the function into onChanged textfield

 TextFormFieldCustom(
              onSaved: (value) => '',
              onChanged: (value) => utangProvider.read(context).filterList(value),
              prefixIcon: Icon(Icons.search),
              hintText: 'Cari...',
            ),

Update

After reading carefully on docs , I think i can implement it using Computed.Family . So i changed previous code to this :


final showFilteredList = Computed.family<List<UtangModel>, String>((read, query) {
  final utang = read(utangProvider.state);
  // var tempList = [...utang];

  return utang
      .where((element) => element.pengutang.nameUser.toLowerCase().contains(query.toLowerCase()))
      .toList();
});

this how i call in UI

Consumer((ctx, read) {
              final utang = read(showFilteredList(_queryController.text));
              return ListView.separated(
                shrinkWrap: true,
                itemCount: utang.length,
                separatorBuilder: (BuildContext context, int index) {
                  return Divider();
                },
                itemBuilder: (BuildContext context, int index) {
                  final result = utang[index];
                  return Card(
                    child: Center(
                      child: Text(result.pengutang.nameUser),
                    ),
                  );
                },
              );
            }),

But i get same result from previous code, I missing something ?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.