A simple way to access state while robust and testable.

Overview

Build Status codecov Star on Github License: MIT Discord Buy Me A Coffee

Riverpod


A state-management library that:

  • catches programming errors at compile time rather than at runtime
  • removes nesting for listening/combining objects
  • ensures that the code is testable
riverpod pub package
flutter_riverpod pub package
hooks_riverpod pub package

Welcome to Riverpod!

This project can be considered as a rewrite of provider to make improvements that would be otherwise impossible.

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

Long story short:

  • Declare your providers as global variables:

    final counterProvider = StateNotifierProvider((ref) {
      return Counter();
    });
    
    class Counter extends StateNotifier<int> {
      Counter(): super(0);
    
      void increment() => state++;
    }
  • Use them inside your widgets in a compile time safe way. No runtime exceptions!

    class Example extends ConsumerWidget {
      @override
      Widget build(BuildContext context, ScopedReader watch) {
        final count = watch(counterProvider);
        return Text(count.toString());
      }
    }

See the FAQ if you have questions about what this means for provider.

Index

Motivation

If provider is a simplification of InheritedWidgets, then Riverpod is a reimplementation of InheritedWidgets from scratch.

It is very similar to provider in principle, but also has major differences as an attempt to fix the common problems that provider face.

Riverpod has multiple goals. First, it inherits the goals of provider:

  • Being able to safely create, observe and dispose states without having to worry about losing the state on widget rebuild.
  • Making our objects visible in Flutter's devtool by default.
  • Testable and composable
  • Improve the readability of InheritedWidgets when we have multiple of them (which would naturally lead to a deeply nested widget tree).
  • Make apps more scalable with a unidirectional data-flow.

From there, Riverpod goes a few steps beyond:

  • Reading objects is now compile-safe. No more runtime exception.
  • It makes the provider pattern more flexible, which allows supporting commonly requested features like:
    • Being able to have multiple providers of the same type.
    • Disposing the state of a provider when it is no longer used.
    • Have computed states
    • Making a provider private.
  • Simplifies complex object graphs. It is easier to depend on asynchronous state.
  • Makes the pattern independent from Flutter

These are achieved by no longer using InheritedWidgets. Instead, Riverpod implements its own mechanism that works in a similar fashion.

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

Contributing

Contributions are welcomed!

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
  • Update the documentation / add examples
  • Implement new features by making a pull-request

FAQ

Why another project when provider already exists?

While provider is largely used and well accepted by the community, it is not perfect either.

People regularly file issues or ask questions about some problems they face, such as:

  • Why do I have a ProviderNotFoundException?
  • How can I make that my state automatically disposed of when not used anymore?
  • How to make a provider that depends on other (potentially complex) providers?

These are legitimate problems, and I believe that something can be improved to fix those.

The issue is, these problems are deeply rooted in how provider works, and fixing those problems is likely impossible without drastic changes to the mechanism of provider.

In a way, if provider is a candle then Riverpod is a lightbulb. They have very similar usages, but we cannot create a lightbulb by improving our candle.

Is it safe to use in production?

Yes, but with caution.

Riverpod recently left its experimental status, but it isn't fully stable either. The API may change slightly when more features are added, and some use-cases may not be as simple as they could be.

But overall, you should be able to use Riverpod without trouble.

Will this get merged with provider at some point?

No. At least not until it is proven that the community likes Riverpod and that it doesn't cause more problems than it solves.

While provider and this project have a lot in common, they do have some major differences. Differences big enough that it would be a large breaking change for users of provider to migrate Riverpod.

Considering that, separating both projects initially sounds like a better compromise.

Will provider be deprecated/stop being supported?

Not in the short term, no.

This project is still experimental and unpopular. While it is, in a way, a provider 2.0, its worth has yet to be proven.

Until it is certain that Riverpod is a better way of doing things and that the community likes it, provider will still be maintained.

Comments
  • [RFC] Unifying syntax for listening to providers (v2)

    [RFC] Unifying syntax for listening to providers (v2)

    This RFC is a follow-up to https://github.com/rrousselGit/river_pod/issues/246 with a slightly different proposal.

    The problems are the same:

    • Riverpod needs a way to add new ways of "listening" to a provider (such as an equivalent to ProviderListener that doesn't involve nesting, but not exclusively)
    • Adding parameters to "build"/"builder" of ConsumerWidget/Consumer would be a large breaking change
    • StatefulWidgets may want to listen to providers without having to resort to Consumer
    • having a different syntax between reading a provider from another provider and reading a provider from a widget causes confusion

    See https://github.com/rrousselGit/river_pod/issues/246 for a bit more explanation

    Proposal

    Instead of passing directly "watch" as parameter to widgets, Riverpod could do like with its providers and pass a "ref" object"

    As such, instead of:

    class StatelessExample extends ConsumerWidget {
      @override
      Widget build(BuildContext context, ScopedReader watch) {
        A value = watch(a);
      }
    }
    

    we'd have:

    class StatelessExample extends ConsumerWidget {
      @override
      Widget build(BuildContext context, WidgetReference ref) {
        A value = ref.watch(a);
      }
    }
    

    Similarly, Consumer would become:

    Consumer(
      builder: (context, ref, child) {
        A value = ref.watch(a);
      },
    );
    

    The behaviour would be strictly identical. But this then allows Riverpod to add extra methods on WidgetsReference, which could allow:

    class StatelessExample extends ConsumerWidget {
      @override
      Widget build(BuildContext context, WidgetReference ref) {
        ref.listen<A>(a, (value) {
          print('provider a changed $value');
        });
      }
    }
    

    This would be equivalent to ProviderListener but without involving nesting.

    Hooks consideration

    While hooks_riverpod doesn't suffer from the problem listed at the start of the issue, the logic wants that hooks_riverpod should also use the same syntax too (both to reduce confusion and simplify maintenance).

    As such, useProvider would be deprecated and a ConsumerHookWidget would be introduced. Which means that instead of:

    class HooksExample extends HookWidget {
      @override
      Widget build(BuildContext context) {
        A value = useProvider(a);
      }
    }
    

    we'd have:

    class HooksExample extends ConsumerHookWidget {
      @override
      Widget build(BuildContext context, WidgetReference ref) {
        A value = ref.watch(a);
      }
    }
    

    This would also clarify that the only purpose of hooks_riverpod is to use both hooks and Riverpod simultaneously.

    context.read/context.refresh considerations

    context.read(myProvider) and context.refresh(provider) would be deprecated.

    Instead, ref should now be used. So the previous:

    class StatelessExample extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return ElevatedButton(
          onPressed: () => context.read(counterProvider).state++;
        );
      }
    }
    

    would become:

    class StatelessExample extends ConsumerWidget {
      @override
      Widget build(BuildContext context, WidgetReference ref) {
        return ElevatedButton(
          onPressed: () => ref.read(counterProvider).state++;
        );
      }
    }
    

    (and same thing with refresh)

    This has two side-effects:

    • StatelessWidget can no-longer be used to just "read" providers
    • there is no-longer a name collision between package:provider and Riverpod for context.read, which would simplify migration.

    StatefulWidget consideration

    An optional goal of this change is to support StatefulWidget.

    This could be done by shipping a State mixin that adds a ref property, which would allow us to write:

    class StatefulExample extends StatefulWidget {
       @override
      _StatefulExampleState createState() => _StatefulExampleState();
    }
    
    class _StatefulExampleState extends State<StatefulExample> with ConsumerStateMixin {
      @override
      Widget build(BuildContext context) {
        A value = ref.watch(a);
      }
    }
    

    Note that this is entirely optional, as Consumer can already be used.

    ProviderReference vs WidgetReference

    While the syntax for listening a provider in widgets and providers would now look similar with both being ref.watch(myProvider), it is important to note that ProviderReference and WidgetReference are distinct objects.

    They are not interchangeable, and you could not assign WidgetReference to ProviderReference for example.

    Their main difference is, ProviderReference does not allow interacting with ScopedProviders. On the other hand, WidgetReference do.

    Similarly, it is entirely possible that in the future, some functionalities as added to one without being added to the other (such as https://github.com/rrousselGit/river_pod/pull/302 which allows ProviderReference to manipulate the state of its provider)

    Conclusion

    That's it, thanks for reading!

    As opposed to https://github.com/rrousselGit/river_pod/issues/246, one major difference is that this proposal is "compile safe" without having to rely on a custom linter.
    The downside is that the syntax for reading providers becomes a tiny bit more verbose.

    What do you think of the proposed change?

    Feel free to leave a comment. You can also use :+1: and :-1: to express your opinion. All feedbacks are welcomed!

    enhancement 
    opened by rrousselGit 115
  • Auto dispose after first listener

    Auto dispose after first listener

    Riverpod version 2.0.0-dev.4 adds a disposeDelay feature to all autoDispose providers and to ProviderContainer/ProviderScope. This configures the amount of time before a provider is disposed when it is not listened.

    To avoid timing issues, it would be nice to add a "auto dispose after the provider is listened to once" mode, which make the provider auto disposable only after it is listened to once.

    Example:

    • Some function on screen A initalizes a provider with some initial value and then navigates to screen B.
    • Only screen B watches the provider.
    • Once screen B is disposed, the provider should be disposed.
    enhancement 
    opened by talent-apps 72
  • [RFC] Change on the syntax for listening providers

    [RFC] Change on the syntax for listening providers

    Hello!
    This issue is an open discussion for a potential change on how to consume/combine providers.

    The goal of these changes are:

    • offer a uniformized way to listen to providers (no-longer have ref.watch vs useProvider vs watch)
    • add an equivalent to ProviderListener that works inside providers too
    • revamp ProviderListener not to involve nesting
    • support a ConsumerStatefulWidget
    • support useProvider(myProvider.select((user) => user.name)) in all the places that may want to listen to a provider

    The problem

    At the moment, there are many similar but slightly different syntax for listening to a provider:

    • providers wanting to listen to another provider may use ref.watch(myProvider):
      final provider = Provider((ref) {
        final value = ref.watch(anotherProvider);
      });
      
    • HookWidget may use useProvider(myProvider):
      class Example extends HookWidget {
        @override
        Widget build(BuildContext context) {
          final value = useProvider(anotherProvider);
      
        }
      }
      
    • ConsumerWidget & Consumer may use watch(myProvider):
      class Example extends ConsumerWidget {
        @override
        Widget build(BuildContext context, ScopedReader watch) {
          final value = watch(anotherProvider);
        }
      }
      ...
      Consumer(
        builder: (context, watch, child) {
          final value = watch(anotherProvider);
        }
      )
      
    • all widgets can use ProviderListener but not providers
      class Example extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return ProviderListener<Something>(
          provider: anotherProvider,
          onChange: (context, value) {}
        );
      }
      }
      

    This works fine but is slightly confusing. While in practice, there's only one solution on how to listen to a provider depending on where you are, the fact that the syntax isn't the same everywhere confuses newcomers.

    On top of that, due to how ConsumerWidget/Consumer works, it is inconvenient to add new ways to listen to providers (such as a simplification of ProviderListener that does not involve nesting) because that would require adding parameters to the build method.

    This also means that it is impossible to listen to providers inside StatefulWidget, as it is impossible to add extra parameters to State.build. This requires developers to use Consumer, which decreases readability.

    Proposal

    This proposal is about fusing all of these methods for listening providers into two static functions:

    • watch, the equivalent of ref.watch/useProvider/...
    • listen, the equivalent of ProviderListener

    These two functions would work in all providers and inside ConsumerWidget, Consumer, and two new additions:

    • ConsumerHookWidget
    • ConsumerStatefulWidget

    Long story short, here is how both functions would look like in practice:

    final a = Provider<A>(...);
    
    final b = Provider((ref) {
      A value = watch(a);
      listen<A>(a, (value) {
      });
    });
    
    Consumer(
      builder: (context) {
        A value = watch(a);
        listen<A>(a, (value) {
        });
      },
    );
    
    class StatelessExample extends ConsumerWidget {
      @override
      Widget build(BuildContext context) {
        A value = watch(a);
        listen<A>(a, (value) {
        });
    
      }
    }
    
    class HooksExample extends ConsumerHookWidget {
      @override
      Widget build(BuildContext context) {
        A value = watch(a);
        listen<A>(a, (value) {
        });
    
      }
    }
    
    class StatefulExample extends ConsumerStatefulWidget {
       @override
      _StatefulExampleState createState() => _StatefulExampleState();
    }
    
    class _StatefulExampleState extends State<StatefulExample> {
      @override
      Widget build(BuildContext context) {
        A value = watch(a);
        listen<A>(a, (value) {
        });
    
      }
    }
    

    This change would involve:

    • deprecating useProvider in favor of ConsumerHookWidget + watch
    • deprecating ProviderListener in favor of listen
    • deprecating ref.watch in favor of watch
    • removing the extra parameter of ConsumerWidget.build

    This change would have no impact on <ref/context>.read

    The downside

    The main issue with this change is, we lose some of the "compilation safety".

    More specifically, there are two cases that currently purposefully do not compile but would now compile (and throw) after this change:

    • reading a ScopedProvider inside a non-scoped provider:

      final scoped = ScopedProvider(...)
      
      final provider = Provider((ref) {
        watch(scoped);
      });
      
    • reading an .autoDispose provider inside a provider that is not marked with .autoDispose:

      final autoDispose = Provider.autoDispose(...)
      
      final provider = Provider((ref) {
        watch(autoDispose);
      });
      

    Since these would now throw exceptions instead of compilation errors, this would make refactoring more difficult.

    The bright side is, there is an alternate solution for these: custom lint rules. Instead of relying on the Dart compiler to have a compilation error, we could extend the Dart analyzer to add support for these scenarios.

    This is a separate project on its own but is feasible.

    Closing word

    That's it~

    What do you think of the proposed change, and what do you think about the downsides?

    Feel free to comment or vote on this issue to express your opinion:

    • vote ๐Ÿš€ if you want this change even without the analyzer plugin (the analyzer plugin would still come but after the release of such change)
    • vote ๐ŸŽ‰ if you want this change, but only if we have the analyzer plugin (this would lock the release of such change until the analyzer plugin is ready)
    • for ๐Ÿ‘Ž if you don't want this change at all
    • leave a comment for any other opinion
    enhancement 
    opened by rrousselGit 56
  • Introduce `when(isRefreshing)` to `AsyncValue` as an optional parameter.

    Introduce `when(isRefreshing)` to `AsyncValue` as an optional parameter.

    As discussed in #1568 I think there are use cases to do the following:

    counter.when(
      data: (data) => Text(
          '$data',
          style: Theme.of(context).textTheme.headline4,
        ),
      error: (error, stackTrace) => const Text('error'), 
      loading: () => const CircularProgressIndicator(),
      isRefreshing: () => const CircularProgressIndicator());
    

    Instead of:

    if (counter.isRefreshing) {
      return Loading();
    }
    
    return counter.when(
      data: (data) => Text(
          '$data',
          style: Theme.of(context).textTheme.headline4,
        ),
      error: (error, stackTrace) => const Text('error'), 
      loading: () => const CircularProgressIndicator());
    

    Especially in cases when the AsyncValue is encapsulated in a styling which should also apply to the isRefreshing part.

    I think isRefreshing could be an optional parameter which adds the desired behaviour.

    enhancement 
    opened by krjw-eyev 40
  • added useProviderListener hook

    added useProviderListener hook

    @rrousselGit I added this to close #163. I based the useProviderListener hook on both ProviderListener code and userProvider hook code. I'll be adding some tests, I just wanted to review this with you first.

    opened by yiss 39
  • Explicit Dependency / Factories

    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.
      } 
    }
    
    enhancement 
    opened by TimWhiting 37
  • Why not call read in the body of the provider?

    Why not call read in the body of the provider?

    I'm confused about this line the docs: image

    Could you elaborate on the rationale?

    Why is this good:

    final repositoryProvider = Provider((ref) => Repository(ref.read));
    class Repository {
       Repository(this.read);
       final Reader read;
       String get token => read(userTokenProvider).state;
    }
    

    But this is bad?

    final repositoryProvider = Provider((ref) => Repository(ref.read(userTokenProvider));
    class Repository {
      Repository(this.token);
       final UserToken token;
       String get token => userToken.state;
    }
    

    It seems from the Repository standpoint it's cleaner to say the thing it wants, rather than concern itself with how that thing is injected. Especially as read opens the Repository full access to all other providers, while passing UserToken tells it only what it needs to know.

    I actually like it even dumber, where it only takes a string, which removes another dependency from the Repository that it need not know about (ie UserToken):

    final repositoryProvider = Provider((ref) => Repository(() => ref.read(userTokenProvider).state);
    class Repository {
      Repository(this.tokenDelegate);
       final String Function() tokenDelegate;
       String get token => tokenDelegate();
    }
    

    This ends up with the most portable code, as this repository is now unconcerned with the DataInjection layer and just needs a simple string builder.

    documentation question 
    opened by esDotDev 36
  • Using

    Using "actors" or event dispatcher

    Hi, the more time I'm spending with Riverpod, the more I'm removing StateNotifier and StateNotifierProvider for just FutureProvider and StreamProvider. It works from me a little like react-query with hooks in one in react word.

    Can't find a good answer for my question: how can we deal with events? I mean something like:

    1. We have a list of Posts.
    2. Using FutureProvider to get all Posts IDs from remote database
    3. Using StreamProvider to watch every particular Post (likes, comments etc.)
    4. Want to send an event to data base to like one of the post, so my StreamProvider from point above, will notify about Post change and will update the data of this particular Post.

    So what is best practice to send this event of like/unlike the Post? Normally I would have a Repository, StateNotifier which takes this Repository and have a method likeOrDisllike. Then I can use something like final controller = useProvider(thisStateNotifierProvider) and on like click do controller.likeOrDislike(). But as I said, with good of Future/Stream Provider I see, there might be 95% of my CRUD app logic with just this two.

    I was thinking about Providing the method from Repository like:

    final actor =
      Provider.family.autoDispose<Future<void>, String>((ref, postId) async {
      final repo = ref.watch(firebaseSpotRepositoryProvider);
      final user = ref.watch(userProvider);
      await repo.likeOrDisslikePost(userId: user.id.getOrCrash(), postId: postId);
    });
    

    The on "UI" :

    Button(
        onTap: () async {
                  context.read(
                    actor(
                      post.id.getOrCrash(),
                    ),
              );
          },
    )
    

    Does it make sense? Or is there a better approach or it's super stupid and whole thinking about resign from any class controllers like StateNotfier is wrong.

    enhancement 
    opened by Chojecki 34
  • FutureProvider disposed unexpectedly in 1.0.0-dev3

    FutureProvider disposed unexpectedly in 1.0.0-dev3

    Describe the bug

    In the following code, future returns error with Bad state: The provider AutoDisposeFutureProvider<String>#25550(example) was disposed before a value was emitted..

    v0.14.0+3 works fine.

    To Reproduce

    final controllerProvider =
        StateNotifierProvider<Controller, List<Future<String>>>(
            (ref) => Controller(ref.read));
    
    final futureProvider =
        FutureProvider.autoDispose.family<String, String>((ref, str) async {
      final ret = await Future.delayed(Duration(seconds: 1), () => str);
      ref.maintainState = true;
      return ret;
    });
    
    class Controller extends StateNotifier<List<Future<String>>> {
      Controller(this._read) : super([]);
    
      Reader _read;
    
      void add(String str) {
        final f = _read(futureProvider(str).future);
        state = [f, ...state];
      }
    }
    
    class MyHomePage extends ConsumerWidget {
      const MyHomePage({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context, WidgetRef ref) {
        final items = ref.watch(controllerProvider);
    
        return Scaffold(
          floatingActionButton: FloatingActionButton(
            onPressed: () {
              ref.read(controllerProvider.notifier).add("example");
            },
            child: const Icon(Icons.add),
          ),
          body: ListView.builder(
            itemCount: items.length,
            itemBuilder: (context, index) {
              return FutureBuilder(
                future: items[index],
                builder: (context, snapshot) {
                  if (snapshot.hasError) {
                    return ListTile(
                      title: Text("${snapshot.error}"),
                    );
                  }
                  if (!snapshot.hasData) {
                    return const ListTile(
                      title: Center(child: CircularProgressIndicator()),
                    );
                  }
                  return ListTile(
                    title: Text("${snapshot.data}"),
                  );
                },
              );
            },
          ),
        );
      }
    }
    

    Expected behavior

    Show 'example' in ListTile.

    bug question 
    opened by limenote135 32
  • Why watching future goes to the loading state first?

    Why watching future goes to the loading state first?

    Describe the bug I just switched my app from flutter_bloc to river_pod and I'm pretty happy. Thank you for the wonderful work.

    However, I did notice one issue. I'm chaining a lot of stream providers and find that using await ref.watch(stream_provider.future) goes to the loading state first, even though the data is already available. See the below simple repro.

    To Reproduce

    Code
    import 'package:flutter/material.dart';
    import 'package:flutter_riverpod/flutter_riverpod.dart';
    
    class Logger extends ProviderObserver {
      @override
      void didUpdateProvider(
        ProviderBase provider,
        Object? previousValue,
        Object? newValue,
        ProviderContainer container,
      ) {
        debugPrint('${provider.name}, $newValue');
      }
    }
    
    Stream<String> text() async* {
      yield 'hello';
      await Future.delayed(const Duration(seconds: 1));
      yield 'hello again';
    }
    
    final textProvider = StreamProvider((ref) => text(), name: 'text');
    
    final firstProvider = StreamProvider((ref) async* {
      final text = await ref.watch(textProvider.future);
      yield 'first $text';
    }, name: 'first');
    
    final secondProvider = StreamProvider((ref) async* {
      final text = await ref.watch(firstProvider.future);
      yield 'second $text';
    }, name: 'second');
    
    void main() {
      runApp(ProviderScope(observers: [Logger()], child: const MyApp()));
    }
    
    class MyApp extends ConsumerWidget {
      const MyApp({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context, WidgetRef ref) {
        final text = ref.watch(secondProvider);
        debugPrint('MyApp: ${text.toString()}');
        return Container();
      }
    }
    
    Log output
    flutter: MyApp: AsyncLoading<String>()
    flutter: text, AsyncData<String>(value: hello)
    flutter: first, AsyncData<String>(value: first hello)
    flutter: second, AsyncData<String>(value: second first hello)
    flutter: MyApp: AsyncData<String>(value: second first hello)
    flutter: text.future, Instance of 'Future<String>'
    flutter: text, AsyncData<String>(value: hello again)
    flutter: first.future, Instance of 'Future<String>'
    flutter: first, AsyncData<String>(isLoading: true, value: first hello)
    flutter: second, AsyncData<String>(isLoading: true, value: second first hello)
    flutter: MyApp: AsyncData<String>(isLoading: true, value: second first hello)
    flutter: first, AsyncData<String>(value: first hello again)
    flutter: second, AsyncData<String>(value: second first hello again)
    flutter: MyApp: AsyncData<String>(value: second first hello again)
    

    As you can see from the log. Even though we got hello again, firstProvider and secondProvider went to loading state first, which in my mind is totally unnecessary. They should have the data already.

    This is problematic that the app might show an unnecessary progress indicator if it responds to isLoading field.

    Related question, what's the difference between isLoading in AsyncData vs AsyncLoading?

    bug needs triage 
    opened by terryl1900 30
  • Protesting Removal of useProvider and HookWidget

    Protesting Removal of useProvider and HookWidget

    In hooks_riverpod 1.0.0-dev.4 .. You are removing useProvider . Most of us moved from provider to riverpod to reduce the boilerplate code. Can you please bring it back ? It's removal will break more than 10 apps my team and I have put into production already.

    You were selling riverpod as provider but different. I see no difference in deprecating some core functionalities. Bring back HookWidget

    PLEASE @rrousselGit

    enhancement needs triage 
    opened by wazini-john 30
  • Cast error when stubbing a generated provider family

    Cast error when stubbing a generated provider family

    Describe the bug When running the reproduction test I receive a cast error. It can be that I misunderstood the usage of the generated provider but couldn't get it out of the docs. Let me know and I can help improve the docs.

    Tap to expand stacktrace โ•โ•โ•ก EXCEPTION CAUGHT BY WIDGETS LIBRARY โ•žโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• The following _CastError was thrown building SimpleWidget(dirty, dependencies: [UncontrolledProviderScope], state: _ConsumerState#f3702): type '_ProductNotifierStub' is not a subtype of type 'AutoDisposeNotifier' in type cast

    The relevant error-causing widget was: SimpleWidget When the exception was thrown, this was the stack: #1 _ExternalProviderSubscription.read (package:riverpod/src/framework/provider_base.dart:179:29) #2 ConsumerStatefulElement.watch (package:flutter_riverpod/src/consumer.dart:560:8) #3 SimpleWidget.build (package:recipe_configuration_ui_v2/src/repo.dart:16:23) #4 _ConsumerState.build (package:flutter_riverpod/src/consumer.dart:477:19) #5 StatefulElement.build (package:flutter/src/widgets/framework.dart:4992:27) #6 ConsumerStatefulElement.build (package:flutter_riverpod/src/consumer.dart:538:20) #7 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4878:15) #8 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:5050:11) #9 Element.rebuild (package:flutter/src/widgets/framework.dart:4604:5) #10 ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:4859:5) #11 StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:5041:11) #12 ComponentElement.mount (package:flutter/src/widgets/framework.dart:4853:5) ... Normal element mounting (25 frames) #37 Element.inflateWidget (package:flutter/src/widgets/framework.dart:3863:16) #38 MultiChildRenderObjectElement.inflateWidget (package:flutter/src/widgets/framework.dart:6435:36) #39 MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6447:32) ... Normal element mounting (379 frames) #418 Element.inflateWidget (package:flutter/src/widgets/framework.dart:3863:16) #419 MultiChildRenderObjectElement.inflateWidget (package:flutter/src/widgets/framework.dart:6435:36) #420 MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6447:32) ... Normal element mounting (422 frames) #842 _UncontrolledProviderScopeElement.mount (package:flutter_riverpod/src/framework.dart:309:11) ... Normal element mounting (9 frames) #851 Element.inflateWidget (package:flutter/src/widgets/framework.dart:3863:16) #852 Element.updateChild (package:flutter/src/widgets/framework.dart:3586:20) #853 RenderObjectToWidgetElement._rebuild (package:flutter/src/widgets/binding.dart:1195:16) #854 RenderObjectToWidgetElement.update (package:flutter/src/widgets/binding.dart:1172:5) #855 RenderObjectToWidgetElement.performRebuild (package:flutter/src/widgets/binding.dart:1186:7) #856 Element.rebuild (package:flutter/src/widgets/framework.dart:4604:5) #857 BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2667:19) #858 AutomatedTestWidgetsFlutterBinding.drawFrame (package:flutter_test/src/binding.dart:1191:19) #859 RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:378:5) #860 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1175:15) #861 SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1104:9) #862 AutomatedTestWidgetsFlutterBinding.pump. (package:flutter_test/src/binding.dart:1057:9) #865 TestAsyncUtils.guard (package:flutter_test/src/test_async_utils.dart:71:41) #866 AutomatedTestWidgetsFlutterBinding.pump (package:flutter_test/src/binding.dart:1043:27) #867 WidgetTester.pumpWidget. (package:flutter_test/src/widget_tester.dart:554:22) #870 TestAsyncUtils.guard (package:flutter_test/src/test_async_utils.dart:71:41) #871 WidgetTester.pumpWidget (package:flutter_test/src/widget_tester.dart:551:27) #872 main. (repo_test.dart:8:18) #873 testWidgets.. (package:flutter_test/src/widget_tester.dart:171:29) #875 ProviderContainer.listen (package:riverpod/src/framework/container.dart:273:21) #876 ConsumerStatefulElement.watch. (package:flutter_riverpod/src/consumer.dart:556:25) #877 _LinkedHashMapMixin.putIfAbsent (dart:collection-patch/compact_hash.dart:527:23) #878 ConsumerStatefulElement.watch (package:flutter_riverpod/src/consumer.dart:549:26) #879 SimpleWidget.build (package:recipe_configuration_ui_v2/src/repo.dart:16:23) #880 _ConsumerState.build (package:flutter_riverpod/src/consumer.dart:477:19) #881 StatefulElement.build (package:flutter/src/widgets/framework.dart:4992:27) #882 ConsumerStatefulElement.build (package:flutter_riverpod/src/consumer.dart:538:20) #883 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4878:15) #884 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:5050:11) #885 Element.rebuild (package:flutter/src/widgets/framework.dart:4604:5) #886 ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:4859:5) #887 StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:5041:11) #888 ComponentElement.mount (package:flutter/src/widgets/framework.dart:4853:5) ... Normal element mounting (25 frames) #913 Element.inflateWidget (package:flutter/src/widgets/framework.dart:3863:16) #914 MultiChildRenderObjectElement.inflateWidget (package:flutter/src/widgets/framework.dart:6435:36) #915 MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6447:32) ... Normal element mounting (379 frames) #1294 Element.inflateWidget (package:flutter/src/widgets/framework.dart:3863:16) #1295 MultiChildRenderObjectElement.inflateWidget (package:flutter/src/widgets/framework.dart:6435:36) #1296 MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6447:32) ... Normal element mounting (422 frames) #1718 _UncontrolledProviderScopeElement.mount (package:flutter_riverpod/src/framework.dart:309:11) ... Normal element mounting (9 frames) #1727 Element.inflateWidget (package:flutter/src/widgets/framework.dart:3863:16) #1728 Element.updateChild (package:flutter/src/widgets/framework.dart:3586:20) #1729 RenderObjectToWidgetElement._rebuild (package:flutter/src/widgets/binding.dart:1195:16) #1730 RenderObjectToWidgetElement.update (package:flutter/src/widgets/binding.dart:1172:5) #1731 RenderObjectToWidgetElement.performRebuild (package:flutter/src/widgets/binding.dart:1186:7) #1732 Element.rebuild (package:flutter/src/widgets/framework.dart:4604:5) #1733 BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2667:19) #1734 AutomatedTestWidgetsFlutterBinding.drawFrame (package:flutter_test/src/binding.dart:1191:19) #1735 RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:378:5) #1736 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1175:15) #1737 SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1104:9) #1738 AutomatedTestWidgetsFlutterBinding.pump. (package:flutter_test/src/binding.dart:1057:9) #1741 TestAsyncUtils.guard (package:flutter_test/src/test_async_utils.dart:71:41) #1742 AutomatedTestWidgetsFlutterBinding.pump (package:flutter_test/src/binding.dart:1043:27) #1743 WidgetTester.pumpWidget. (package:flutter_test/src/widget_tester.dart:554:22) #1746 TestAsyncUtils.guard (package:flutter_test/src/test_async_utils.dart:71:41) #1747 WidgetTester.pumpWidget (package:flutter_test/src/widget_tester.dart:551:27) #1748 main. (repo_test.dart:8:18) #1749 testWidgets.. (package:flutter_test/src/widget_tester.dart:171:29) #1751 testWidgets.. (package:flutter_test/src/widget_tester.dart:170:25) #1752 TestWidgetsFlutterBinding._runTestBody (package:flutter_test/src/binding.dart:841:19) #1754 TestWidgetsFlutterBinding._runTestBody (package:flutter_test/src/binding.dart:831:5) #1757 TestWidgetsFlutterBinding._runTest (package:flutter_test/src/binding.dart:820:14) #1758 AutomatedTestWidgetsFlutterBinding.runTest. (package:flutter_test/src/binding.dart:1247:24) #1759 FakeAsync.run.. (package:fake_async/fake_async.dart:182:54) #1764 withClock (package:clock/src/default.dart:52:10) #1765 FakeAsync.run. (package:fake_async/fake_async.dart:182:22) #1770 FakeAsync.run (package:fake_async/fake_async.dart:182:7) #1771 AutomatedTestWidgetsFlutterBinding.runTest (package:flutter_test/src/binding.dart:1244:15) #1772 testWidgets. (package:flutter_test/src/widget_tester.dart:164:24) #1773 Declarer.test.. (package:test_api/src/backend/declarer.dart:215:19) #1775 Declarer.test.. (package:test_api/src/backend/declarer.dart:214:9) #1780 Declarer.test. (package:test_api/src/backend/declarer.dart:213:13) #1781 Invoker._waitForOutstandingCallbacks. (package:test_api/src/backend/invoker.dart:257:15) #1786 Invoker._waitForOutstandingCallbacks (package:test_api/src/backend/invoker.dart:254:5) #1787 Invoker._onRun... (package:test_api/src/backend/invoker.dart:391:17) #1789 Invoker._onRun... (package:test_api/src/backend/invoker.dart:389:11) #1794 Invoker._onRun.. (package:test_api/src/backend/invoker.dart:380:9) #1795 Invoker._guardIfGuarded (package:test_api/src/backend/invoker.dart:423:15) #1796 Invoker._onRun. (package:test_api/src/backend/invoker.dart:379:7) #1803 Invoker._onRun (package:test_api/src/backend/invoker.dart:378:11) #1804 LiveTestController.run (package:test_api/src/backend/live_test_controller.dart:153:11) #1805 RemoteListener._runLiveTest. (package:test_api/src/backend/remote_listener.dart:273:16) #1810 RemoteListener._runLiveTest (package:test_api/src/backend/remote_listener.dart:272:5) #1811 RemoteListener._serializeTest. (package:test_api/src/backend/remote_listener.dart:220:7) #1829 _GuaranteeSink.add (package:stream_channel/src/guarantee_channel.dart:125:12) #1830 new _MultiChannel. (package:stream_channel/src/multi_channel.dart:159:31) #1832 CastStreamSubscription._onData (dart:_internal/async_cast.dart:85:11) #1858 new _WebSocketImpl._fromSocket. (dart:_http/websocket_impl.dart:1144:21) #1864 _WebSocketProtocolTransformer._messageFrameEnd (dart:_http/websocket_impl.dart:332:23) #1865 _WebSocketProtocolTransformer.add (dart:_http/websocket_impl.dart:226:46) #1873 _Socket._onData (dart:io-patch/socket_patch.dart:2324:41) #1880 new _RawSocket. (dart:io-patch/socket_patch.dart:1849:33) #1881 _NativeSocket.issueReadEvent.issue (dart:io-patch/socket_patch.dart:1322:14) (elided 108 frames from dart:async and package:stack_trace)

    Exited (1)

    To Reproduce

    Created an extremely simplified reproduction scenario.

    Widget

    class SimpleWidget extends ConsumerWidget {
      const SimpleWidget({
        required this.product,
        super.key,
      });
    
      final Product product;
    
      @override
      Widget build(BuildContext context, WidgetRef ref) {
        final value = ref.watch(productNotifierProvider(Product.coffee));
        return Scaffold(
          body: Text('value: $value'),
        );
      }
    }
    
    @riverpod
    class ProductNotifier extends _$ProductNotifier {
      @override
      int build(Product product) {
        switch (product) {
          case Product.iceCream:
            return 0;
          case Product.coffee:
            return 1;
        }
      }
    }
    
    enum Product { iceCream, coffee }
    

    Test

    void main() {
      testWidgets('Example test', (tester) async {
        await tester.pumpWidget(
          ProviderScope(
            overrides: [
              productNotifierProvider(Product.coffee)
                  .overrideWith(_ProductNotifierStub.new)
            ],
            child: const MaterialApp(
              home: Scaffold(
                body: SimpleWidget(
                  product: Product.coffee,
                ),
              ),
            ),
          ),
        );
    
        await tester.pumpAndSettle();
    
        expect(find.text('value: 1'), findsOneWidget);
      });
    }
    
    class _ProductNotifierStub extends ProductNotifier {
      @override
      int build(Product product) {
        return 1;
      }
    }
    

    Expected behavior Since dart analyzer sees no issues I would expect the test to pass.

    bug 
    opened by remonh87 0
  • Provider rebuilds in infinite loop when KeepAliveLink is closed immediately.

    Provider rebuilds in infinite loop when KeepAliveLink is closed immediately.

    Describe the bug When an auto disposed provider calls ref.keepAlive(); and the KeepAliveLink is closed immediately (so not in an async callback for example), the provider rapidly and indefinitely rebuilds as soon as it is read.

    The riverpod version I used is 2.1.3.

    To Reproduce Run the following code and press the "Test" button:

    import 'package:flutter/material.dart';
    import 'package:flutter_riverpod/flutter_riverpod.dart';
    
    void main() {
      runApp(
        const ProviderScope(child: MyApp()),
      );
    }
    
    final testProvider = Provider.autoDispose<String>((ref) {
      print('create testProvider');
      ref.onDispose(() {
        print('dispose');
      });
      final link = ref.keepAlive();
      link.close();
      return 'value';
    });
    
    class MyApp extends ConsumerWidget {
      const MyApp({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context, WidgetRef ref) {
        return MaterialApp(
          home: Scaffold(
            appBar: AppBar(
              title: const Text('Riverpod bug'),
            ),
            body: Center(
              child: ElevatedButton(
                onPressed: () {
                  print('onPressed');
                  print(ref.read(testProvider));
                },
                child: const Text('Test'),
              ),
            ),
          ),
        );
      }
    }
    
    

    Expected behavior The expected output should be:

    flutter: onPressed
    flutter: create testProvider
    flutter: value
    flutter: dispose
    

    Actual behavior The app freezes and the output is:

    flutter: onPressed
    flutter: create testProvider
    flutter: value
    flutter: dispose
    flutter: create testProvider
    flutter: dispose
    flutter: create testProvider
    flutter: dispose
    flutter: create testProvider
    flutter: dispose
    flutter: create testProvider
    flutter: dispose
    flutter: create testProvider
    flutter: dispose
    flutter: create testProvider
    flutter: dispose
    flutter: create testProvider
    flutter: dispose
    flutter: create testProvider
    flutter: dispose
    flutter: create testProvider
    flutter: dispose
    flutter: create testProvider
    flutter: dispose
    flutter: create testProvider
    flutter: dispose
    flutter: create testProvider
    flutter: dispose
    ...
    
    bug needs triage 
    opened by Quijx 1
  • Assertion failed: _lastFuture == null

    Assertion failed: _lastFuture == null

    Describe the bug Using following chain of providers

    1. AsyncNotifier
    2. AsyncNotifier: .future from 1st provider
    3. AsyncNotifier: .future from 2nd provider

    Will cause following error:

    Log
    โ•โ•โ•ก LOGGER RECORD / SEVERE: 2022-12-30 20:05:04.040 โ•žโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
    ErrorText unknown error.
    Assertion failed: file:///C:/Users/vorob/AppData/Local/Pub/Cache/hosted/pub.dev/riverpod-2.1.3/lib/src/async_notifier/base.dart:333:18
    _lastFuture == null
    "bad state"
    <Debug frame / internal> <unknown>:<unknown>/<unknown>:288:49 throw_ (1 frame)
    <Debug frame / internal> <unknown>:<unknown>/<unknown>:29:3 assertFailed (1 frame)
    package:riverpod/src/async_notifier/base.dart:333:30 <fn> (1 frame)
    package:riverpod/src/async_notifier/base.dart:304:11 <fn> (1 frame)
    package:riverpod/src/async_notifier/base.dart:325:47 [_handleAsync] (1 frame)
    package:riverpod/src/async_notifier/base.dart:271:5 handleFuture (1 frame)
    package:riverpod/src/async_notifier/base.dart:450:9 <fn> (1 frame)
    package:riverpod/src/result.dart:68:16 when (1 frame)
    package:riverpod/src/async_notifier/base.dart:445:19 create (1 frame)
    package:riverpod/src/framework/element.dart:418:7 buildState (1 frame)
    package:riverpod/src/framework/element.dart:356:5 [_performBuild] (1 frame)
    package:riverpod/src/framework/element.dart:319:7 flush (1 frame)
    package:riverpod/src/framework/scheduler.dart:62:40 [_performRefresh] (1 frame)
    package:riverpod/src/framework/scheduler.dart:50:5 [_task] (1 frame)
    package:flutter_riverpod/src/framework.dart:392:12 build (1 frame)
    <Debug frame / flutter internal> package:flutter/src/widgets/framework.dart:4995:15 performRebuild (1 frame)
    <Debug frame / flutter internal> package:flutter/src/widgets/framework.dart:4715:7 rebuild (1 frame)
    <Debug frame / flutter internal> package:flutter/src/widgets/framework.dart:2767:18 buildScope (1 frame)
    <Debug frame / flutter internal> package:flutter/src/widgets/binding.dart:864:9 drawFrame (1 frame)
    <Debug frame / flutter internal> package:flutter/src/rendering/binding.dart:381:5 [_handlePersistentFrameCallback] (1 frame)
    <Debug frame / flutter internal> package:flutter/src/scheduler/binding.dart:1289:15 [_invokeFrameCallback] (1 frame)
    <Debug frame / flutter internal> package:flutter/src/scheduler/binding.dart:1218:9 handleDrawFrame (1 frame)
    <Debug frame / flutter internal> package:flutter/src/scheduler/binding.dart:1076:5 [_handleDrawFrame] (1 frame)
    <Debug frame / internal> <unknown>:<unknown>/<unknown>:1193:13 invoke (1 frame)
    <Debug frame / internal> <unknown>:<unknown>/<unknown>:220:5 invokeOnDrawFrame (1 frame)
    <Debug frame / internal> <unknown>:<unknown>/<unknown>:190:45 <fn> (1 frame)
    <Debug frame / internal> <unknown>:<unknown>/<unknown>:367:37 _checkAndCall (1 frame)
    <Debug frame / internal> <unknown>:<unknown>/<unknown>:372:39 dcall (1 frame)
    โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• 1672419904040000 โ•โ•
    

    To Reproduce

    https://dartpad.dev/?id=b54462f0563ceb81ac6697c24bd79a41

    Expected behavior

    No errors.

    bug needs triage 
    opened by Zekfad 1
  • Allow returning null from the handled states of whenOrNull/mapOrNull

    Allow returning null from the handled states of whenOrNull/mapOrNull

    Describe the bug When using whenOrNull/mapOrNull, we can't assign null to a nullable variable using any of the handled states: data/error/loading. The reason for this is they return type R while the expected generic type to be returned from whenOrNull/mapOrNull is R?.

    To Reproduce

    //Possible
    final x1 = const AsyncValue.data(1).whenOrNull(
      data: (value) => null,
    );
    
    //Possible
    const AsyncValue.data(1).whenOrNull(
      data: (value) => null,
    );
    
    //Impossible
    final int? x2 = const AsyncValue.data(1).whenOrNull(
      data: (value) => null,
    );
    

    Expected behavior I expect to be able to assign null from the handled states of whenOrNull/mapOrNull. This is helpful for cases when I'll conditionally return null/some according to data.

    bug needs triage 
    opened by AhmedLSayed9 0
  • riverpod_generator package should be installed under dev_dependency

    riverpod_generator package should be installed under dev_dependency

    Documentation on installation on pub.dev is wrong. It is missing --dev flag. Command for package installation should be dart pub add riverpod_generator --dev

    Readme is actually stating that package should be in dev_dependencies, but installing tab doesn't.

    Screenshot

    documentation needs triage 
    opened by zigapovhe 0
Owner
Remi Rousselet
Flutter enthusiast. You'll find me on stackoverflow. Or as a speaker in Flutter meetups
Remi Rousselet
Simple global state management for Flutter

Slices Slices is a minimalist state manegement, focused specifically for applications that needs a global state where different "pieces" of the applic

Erick 5 Jun 15, 2021
MobX for the Dart language. Hassle-free, reactive state-management for your Dart and Flutter apps.

Language: English | Portuguรชs | Chinese mobx.dart MobX for the Dart language. Supercharge the state-management in your Dart apps with Transparent Func

MobX 2.2k Dec 27, 2022
A predictable state management library that helps implement the BLoC design pattern

A predictable state management library that helps implement the BLoC design pattern. Package Pub bloc bloc_test flutter_bloc angular_bloc hydrated_blo

Felix Angelov 9.9k Dec 31, 2022
Another state management solution

VxState VxState is a state management library built for Flutter apps with focus on simplicity. It is inspired by StoreKeeper & libraries like Redux, V

Pawan Kumar 42 Dec 24, 2022
A flutter boilerplate project with GetX state management.

flutter_getx_boilerplate Languages: English (this file), Chinese. Introduction During my study of Flutter, I have been using the flutter_bloc state ma

Kevin Zhang 234 Jan 5, 2023
Manage the state of your widgets using imperative programming concepts.

Imperative Flutter Manage the state of your widgets using imperative programming concepts. Setup Intall imperative_flutter package in pubspec.yaml dep

Jeovane Santos 5 Aug 20, 2022
Flutter MVU architecture/state management package

mvu_flutter No mutability. No builders. No connectors. No reducers. No StreamControllers and subscription management. A truly declarative state manage

Yakov Karpov 7 Jul 29, 2021
The modular state management solution for flutter.

The modular state management solution for flutter. Easy debugging : each event is predictable and goes into a single pipeline Centralized state : soli

Aloรฏs Deniel 44 Jul 6, 2022
Example of use bloc + freezed with a state that contains a list

blocfreezedlistexample A new Flutter project. Getting Started This project is a starting point for a Flutter application. A few resources to get you s

Leynier Gutiรฉrrez Gonzรกlez 2 Mar 21, 2022
London App Brewery State Management Project

todey_flutter A new Flutter application. Getting Started This project is a starting point for a Flutter application. A few resources to get you starte

null 0 Nov 1, 2021
Timer based on provider state manager

timer_provider Timer based on provider state manager Getting Started This project is a starting point for a Flutter application. A few resources to ge

ะ•ะปะธะทะฐะฒะตั‚ะฐ ะ›ะพะฑะพะดะธะฝะฐ 0 Nov 6, 2021
Flutter State Management with provider :rocket:

Flutter - Gerenciamento de Estados com Provider Objetivos ao completar os estudos Aprenda a gerenciar o estado da sua aplicaรงรฃo com Single Source of T

Tiago Barbosa 0 Dec 6, 2021
InheritedWidgets, but simple

English | Portuguรชs | ็ฎ€ไฝ“ไธญๆ–‡ | Espaรฑol A wrapper around InheritedWidget to make them easier to use and more reusable. By using provider instead of manua

Remi Rousselet 4.6k Dec 30, 2022
Functional programming in Dart and Flutter. All the main functional programming types and patterns fully documented, tested, and with examples.

Fpdart Functional programming in Dart and Flutter. All the main functional programming types and patterns fully documented, tested, and with examples.

Sandro Maglione 275 Dec 26, 2022
Megaflixz is a movie app for the movie lover in you. Includes all new and upcoming movies and TV series. Also has an option to save movies to watch later list

MegaflixZ MegaflixZ is a movie app for the movie lover in you. It is an app that displays new and upcoming movies and tv series. Team members Deepak M

Deepak Mathews Koshy 11 Aug 23, 2021
Open screens/snackbars/dialogs/bottomSheets without context, manage states and inject dependencies easily with Get.

Languages: English (this file), Indonesian, Urdu, Chinese, Brazilian Portuguese, Spanish, Russian, Polish, Korean, French. About Get Installing Counte

Jonny Borges 8k Jan 8, 2023
App to Watch Animes And Read Manga.

App To Watch Anime And Read Manga NOTE: Manga Section Contains 18+ content. Sometimes App may take some time to load. Constants Folder is removed from

null 8 Sep 12, 2021
A simple and robust way to interact with Anilibria API.

anilibria.dart A simple and robust way to interact with Anilibria API. Example import 'package:anilibria/anilibria.dart'; void main() async { final

Arsenii Liunsha 3 Jun 13, 2022
A state management library that enables concise, fluid, readable and testable business logic code.

Creator is a state management library that enables concise, fluid, readable, and testable business logic code. Read and update state with compile time

Xianzhe Liang 181 Dec 24, 2022
This is not an app. I made this architecture to build robust and easy-to-maintain products but in a faster way.

simple_architecture_flutter This is not an app. I made this architecture to build robust and easy-to-maintain products but in a faster way. Info I use

Batuhan Karababa 9 Oct 28, 2022