hooks_riverpod 0.4.0

  • Readme
  • Changelog
  • Example
  • Installing
  • 91

pub package pub package pub package Build Status

Black Lives Matter. Support the Equal Justice Initiative. #

Welcome to Riverpod!

This project can be considered as an experimental provider rewrite.

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

Long story short:

  • Declare your providers as global variables:

    final myNotifierProvider = ChangeNotifierProvider((_) {
      return MyNotifier();
    });
    
    class MyNotifier extends ChangeNotifier {
      int count;
      // TODO: typical ChangeNotifier logic
    }
    
  • Use them inside your widgets in a compile-time safe way. No runtime exceptions!

    class Example extends HookWidget {
      @override
      Widget build(BuildContext context) {
        final count = useProvider(myNotifierProvider);
        return Text(count.toString());
      }
    }
    

See the FAQ if you have questions around 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? #

The project is still experimental, so use it at your own risk.

It applied all the lessons learned from provider, so I would expect this project to solve most use-cases.
But if your project randomly catches fire, you were warned!

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.

0.4.0 #

Changed the syntax of "AutoDispose*" and "*Family" to use a syntax similar to named constructors instead.

Before:

final myProvider = AutoDisposeStateNotifierProviderFamily<MyStateNotifier, int>((ref, id) {
  return MyStateNotifier(id: id);
});

After:

final myProvider = StateNotifierProvider.autoDispose.family<MyStateNotifier, int>((ref, id) {
  return MyStateNotifier(id: id);
});

The behavior is the same. Only the syntax changed.

0.3.1 #

  • Loosen the version constraint of flutter_hooks used to support latest versions.

0.3.0 #

  • Added AsyncValue.whenData, syntax sugar for AsyncValue.when to handle only the data case and do nothing for the error/loading cases.

  • Fixed a bug that caused [Computed] to crash if it stopped being listened then was listened again.

0.2.1 #

  • useProvider no longer throws an UnsupportedError when the provider listened changes, and correctly listen to the new provider.

  • Computed and Consumer now correctly unsubscribe to a provider when their function stops using a provider.

0.2.0 #

  • ref.read is renamed as ref.dependOn
  • Deprecated ref.dependOn(streamProvider).stream and ref.dependOn(futureProvider).future in favor of a universal ref.dependOn(provider).value.
  • added ref.read(provider), syntax sugar for ref.dependOn(provider).value.

0.1.0 #

Initial release

example/lib/main.dart

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

void main() {
  runApp(
    /// [MyApp] is wrapped in a [ProviderScope].
    /// This widget is where the state of most of our providers will be stored.
    /// This replaces `MultiProvider` if you've used `provider` before.
    const ProviderScope(
      child: MyApp(),
    ),
  );
}

/// A provider that creates and listen to a [StateNotifier].
///
/// Providers are declared as global variables.
/// This does not hinder testability, as the state of a provider is instead
/// stored inside a [ProviderScope].
final counterProvider = StateNotifierProvider<Counter>((_) => Counter());

/// A simple [StateNotifier] that implements a counter.
///
/// It doesn't have to be a [StateNotifier], and could be anything else such as:
/// - [ChangeNotifier], with [ChangeNotifierProvider]
/// - [Stream], with [StreamProvider]
/// ...
class Counter extends StateNotifier<int> {
  Counter() : super(0);

  void increment() => state++;
}

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

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

class MyHomePage extends HookWidget {
  const MyHomePage({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final count = useProvider(counterProvider.state);

    return Scaffold(
      appBar: AppBar(
        title: const Text('Riverpod counter example'),
      ),
      body: Center(
        child: Text(
          '$count',
          style: Theme.of(context).textTheme.headline4,
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () => counterProvider.read(context).increment(),
        child: const Icon(Icons.add),
      ),
    );
  }
}

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  hooks_riverpod: ^0.4.0

2. Install it

You can install packages from the command line:

with Flutter:


$ flutter pub get

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:hooks_riverpod/hooks_riverpod.dart';
  
Popularity:
Describes how popular the package is relative to other packages. [more]
82
Health:
Code health derived from static analysis. [more]
100
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
100
Overall:
Weighted score of the above. [more]
91
Learn more about scoring.

We analyzed this package on Jul 10, 2020, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.8.4
  • pana: 0.13.14
  • Flutter: 1.17.5

Analysis suggestions

Package not compatible with SDK dart

Because:

  • hooks_riverpod that is a package requiring null.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.8.0 <3.0.0
collection ^1.14.12 1.14.12 1.14.13
flutter 0.0.0
flutter_hooks >=0.11.0 <2.0.0 0.11.0
flutter_riverpod ^0.4.0 0.4.0
riverpod ^0.4.0 0.4.0
state_notifier ^0.5.0 0.5.0
Transitive dependencies
freezed_annotation 0.11.0
json_annotation 3.0.1
meta 1.1.8 1.2.2
sky_engine 0.0.99
typed_data 1.1.6 1.2.0
vector_math 2.0.8 2.1.0-nullsafety
Dev dependencies
flutter_test
mockito ^4.1.0