Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: rrousselGit/riverpod
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: riverpod_generator-v2.3.8
Choose a base ref
...
head repository: rrousselGit/riverpod
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: riverpod_generator-v2.3.9
Choose a head ref
  • 7 commits
  • 25 files changed
  • 3 contributors

Commits on Nov 21, 2023

  1. Copy the full SHA
    a045dee View commit details
  2. Typos (#3143)

    rrousselGit authored Nov 21, 2023
    Copy the full SHA
    312a7a1 View commit details

Commits on Nov 23, 2023

  1. fixed a typo (#3149)

    daveragos authored Nov 23, 2023
    Copy the full SHA
    036eac1 View commit details

Commits on Nov 26, 2023

  1. Copy the full SHA
    b7056b5 View commit details
  2. Copy the full SHA
    8158609 View commit details
  3. Fix infinite loop due to keepAlive (#3158)

    Fix ref.exists not checking ancestor containers.
    
    fixes #2177
    fixes #2044
    rrousselGit authored Nov 26, 2023
    Copy the full SHA
    dc5b34d View commit details
  4. The following packages have been updated: (#3161)

    riverpod            : 2.4.8 -> 2.4.9
    riverpod_annotation : 2.3.2 -> 2.3.3
    riverpod_generator  : 2.3.8 -> 2.3.9
    riverpod_lint       : 2.3.6 -> 2.3.7
    flutter_riverpod    : 2.4.8 -> 2.4.9
    hooks_riverpod      : 2.4.8 -> 2.4.9
    rrousselGit authored Nov 26, 2023
    Copy the full SHA
    95ac564 View commit details
4 changes: 0 additions & 4 deletions .github/workflows/check_generation.yml
Original file line number Diff line number Diff line change
@@ -2,14 +2,10 @@ name: Check code-generation

on:
pull_request:
paths-ignore:
- "**.md"
push:
branches:
- master
- dev
paths-ignore:
- "**.md"

jobs:
check_generation:
19 changes: 19 additions & 0 deletions .github/workflows/cleanup.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
name: Cleanup Workflow

on:
workflow_run:
workflows:
- "build"
- "changelog"
- check_generation
- riverpod_lint
types:
- completed

jobs:
cleanup:
runs-on: ubuntu-latest

steps:
- name: Cleanup
run: echo "This is the cleanup job."
8 changes: 8 additions & 0 deletions packages/flutter_riverpod/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
## 2.4.9 - 2023-11-27

- Fix "pending timer" issue inside tests when using `ref.keepAlive()`.
- Fix `Ref.invalidate`/`Ref.refresh` not throwing on circular dependency.
- Fix an infinite loop caused by `ref.keepAlive` if the `KeepAliveLink` is immediately closed.
- Fix `container.exists(provider)` on nested containers not checking their
parent containers.

## 2.4.8 - 2023-11-20

Fix exceptions when using multiple root `ProviderContainers`/`ProviderScopes`.
4 changes: 2 additions & 2 deletions packages/flutter_riverpod/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@ name: flutter_riverpod
description: >
A simple way to access state from anywhere in your application
while robust and testable.
version: 2.4.8
version: 2.4.9
homepage: https://riverpod.dev
repository: https://github.com/rrousselGit/riverpod
issue_tracker: https://github.com/rrousselGit/riverpod/issues
@@ -18,7 +18,7 @@ dependencies:
flutter:
sdk: flutter
meta: ^1.4.0
riverpod: 2.4.8
riverpod: 2.4.9
state_notifier: ">=0.7.2 <2.0.0"

dev_dependencies:
23 changes: 23 additions & 0 deletions packages/flutter_riverpod/test/consumer_test.dart
Original file line number Diff line number Diff line change
@@ -6,6 +6,29 @@ import 'package:flutter_test/flutter_test.dart';
import 'utils.dart';

void main() {
testWidgets('Riverpod test', (tester) async {
// Regression test for https://github.com/rrousselGit/riverpod/pull/3156

final streamProvider = StreamProvider.autoDispose((ref) async* {});
final provider1 = Provider.autoDispose((ref) {
ref.keepAlive();

ref.watch(streamProvider);
});

await tester.pumpWidget(
ProviderScope(
child: Consumer(
builder: (context, ref, child) {
ref.watch(provider1);

return const SizedBox();
},
),
),
);
});

testWidgets('Passes key', (tester) async {
await tester.pumpWidget(
ProviderScope(
8 changes: 8 additions & 0 deletions packages/hooks_riverpod/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
## 2.4.9 - 2023-11-27

- Fix "pending timer" issue inside tests when using `ref.keepAlive()`.
- Fix `Ref.invalidate`/`Ref.refresh` not throwing on circular dependency.
- Fix an infinite loop caused by `ref.keepAlive` if the `KeepAliveLink` is immediately closed.
- Fix `container.exists(provider)` on nested containers not checking their
parent containers.

## 2.4.8 - 2023-11-20

Fix exceptions when using multiple root `ProviderContainers`/`ProviderScopes`.
6 changes: 3 additions & 3 deletions packages/hooks_riverpod/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@ name: hooks_riverpod
description: >
A simple way to access state from anywhere in your application
while robust and testable.
version: 2.4.8
version: 2.4.9
homepage: https://riverpod.dev
repository: https://github.com/rrousselGit/riverpod
issue_tracker: https://github.com/rrousselGit/riverpod/issues
@@ -18,8 +18,8 @@ dependencies:
flutter:
sdk: flutter
flutter_hooks: '>=0.18.0 <0.21.0'
flutter_riverpod: 2.4.8
riverpod: 2.4.8
flutter_riverpod: 2.4.9
riverpod: 2.4.9
state_notifier: ">=0.7.2 <2.0.0"

dev_dependencies:
8 changes: 8 additions & 0 deletions packages/riverpod/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
## 2.4.9 - 2023-11-27

- Fix "pending timer" issue inside tests when using `ref.keepAlive()`.
- Fix `Ref.invalidate`/`Ref.refresh` not throwing on circular dependency.
- Fix an infinite loop caused by `ref.keepAlive` if the `KeepAliveLink` is immediately closed.
- Fix `container.exists(provider)` on nested containers not checking their
parent containers.

## 2.4.8 - 2023-11-20

Fix exceptions when using multiple root `ProviderContainers`/`ProviderScopes`.
45 changes: 29 additions & 16 deletions packages/riverpod/lib/src/framework/container.dart
Original file line number Diff line number Diff line change
@@ -243,7 +243,7 @@ class ProviderContainer implements Node {

/// {@macro riverpod.exists}
bool exists(ProviderBase<Object?> provider) {
final element = _stateReaders[provider]?._element;
final element = _getOrNull(provider)?._element;

return element != null;
}
@@ -306,9 +306,9 @@ class ProviderContainer implements Node {
/// {@macro riverpod.invalidate}
void invalidate(ProviderOrFamily provider) {
if (provider is ProviderBase) {
final reader = _getStateReader(provider._origin);
final reader = _getOrNull(provider);

reader._element?.invalidateSelf();
reader?._element?.invalidateSelf();
} else {
provider as Family;

@@ -329,18 +329,21 @@ class ProviderContainer implements Node {
}

void _disposeProvider(ProviderBase<Object?> provider) {
final element = readProviderElement(provider);
element.dispose();
final reader = _getOrNull(provider);
// The provider is already disposed, so we don't need to do anything
if (reader == null) return;

final reader = _stateReaders[element._origin]!;
reader._element?.dispose();

if (reader.isDynamicallyCreated) {
// Since the StateReader is implicitly created, we don't keep it
// on provider dispose, to avoid memory leak

void removeStateReaderFrom(ProviderContainer container) {
if (container._stateReaders[element._origin] == reader) {
container._stateReaders.remove(element._origin);
/// Checking if the reader is the same instance is important,
/// as it is possible that the provider was overridden.
if (container._stateReaders[provider] == reader) {
container._stateReaders.remove(provider);
}
container._children.forEach(removeStateReaderFrom);
}
@@ -439,7 +442,7 @@ class ProviderContainer implements Node {
);
}

final reader = _getStateReader(provider);
final reader = _putIfAbsent(provider);

assert(
() {
@@ -493,7 +496,20 @@ final b = Provider((ref) => ref.watch(a), dependencies: [a]);
return reader.getElement() as ProviderElementBase<State>;
}

_StateReader _getStateReader(ProviderBase<Object?> provider) {
/// Obtains a [_StateReader] for a provider, but do not create it if it does
/// not exist.
_StateReader? _getOrNull(ProviderBase<Object?> provider) {
return _stateReaders[provider] ??

/// No need to check "parent". We can directly check "root", because
/// if the provider is not in the root, it must have been overridden.
/// In which case, it is guaranteed to be in the current container already.
_root?._getOrNull(provider);
}

/// Create a [_StateReader] for a provider if it does not exist.
/// If one already exists, returns it.
_StateReader _putIfAbsent(ProviderBase<Object?> provider) {
final currentReader = _stateReaders[provider];
if (currentReader != null) return currentReader;

@@ -624,19 +640,16 @@ final b = Provider((ref) => ref.watch(a), dependencies: [a]);
/// This will destroy the state of all providers associated with this
/// [ProviderContainer] and call [Ref.onDispose] listeners.
void dispose() {
if (_disposed) {
return;
}
if (_disposed) return;

_disposed = true;
_parent?._children.remove(this);

_disposed = true;
if (_root == null) scheduler.dispose();

for (final element in getAllProviderElementsInOrder().toList().reversed) {
element.dispose();
}

if (_root == null) scheduler.dispose();
}

/// Traverse the [ProviderElementBase]s associated with this [ProviderContainer].
4 changes: 3 additions & 1 deletion packages/riverpod/lib/src/framework/element.dart
Original file line number Diff line number Diff line change
@@ -287,6 +287,7 @@ abstract class ProviderElementBase<State> implements Ref<State>, Node {

@override
void invalidate(ProviderOrFamily provider) {
assert(_debugAssertCanDependOn(provider), '');
_container.invalidate(provider);
}

@@ -615,7 +616,7 @@ The provider ${_debugCurrentlyBuildingElement!.origin} modified $origin while bu
);
}

bool _debugAssertCanDependOn(ProviderListenable<Object?> listenable) {
bool _debugAssertCanDependOn(ProviderListenableOrFamily listenable) {
assert(
() {
if (listenable is! ProviderBase<Object?>) return true;
@@ -678,6 +679,7 @@ The provider ${_debugCurrentlyBuildingElement!.origin} modified $origin while bu
@override
T refresh<T>(Refreshable<T> provider) {
_assertNotOutdated();
assert(_debugAssertCanDependOn(provider), '');
return _container.refresh(provider);
}

7 changes: 5 additions & 2 deletions packages/riverpod/lib/src/framework/foundation.dart
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@ part of '../framework.dart';

/// A common interface shared by [ProviderBase] and [Family]
@sealed
abstract class ProviderOrFamily {
abstract class ProviderOrFamily implements ProviderListenableOrFamily {
/// A common interface shared by [ProviderBase] and [Family]
const ProviderOrFamily({
required this.name,
@@ -81,6 +81,9 @@ abstract class ProviderOrFamily {
final Iterable<ProviderOrFamily>? allTransitiveDependencies;
}

/// A shared interface between [ProviderListenable] and [Family].
abstract class ProviderListenableOrFamily {}

/// Computes the list of all dependencies of a provider.
@internal
Set<ProviderOrFamily>? computeAllTransitiveDependencies(
@@ -132,7 +135,7 @@ String shortHash(Object? object) {
///
/// Should override ==/hashCode when possible
@immutable
mixin ProviderListenable<State> {
mixin ProviderListenable<State> implements ProviderListenableOrFamily {
/// Starts listening to this transformer
ProviderSubscription<State> addListener(
Node node,
11 changes: 10 additions & 1 deletion packages/riverpod/lib/src/framework/scheduler.dart
Original file line number Diff line number Diff line change
@@ -17,6 +17,8 @@ void _defaultVsync(void Function() task) {
/// Providers are disposed if they spent at least one full frame without any listener.
@internal
class ProviderScheduler {
var _disposed = false;

/// A way to override [vsync], used by Flutter to synchronize a container
/// with the widget tree.
@internal
@@ -61,7 +63,13 @@ class ProviderScheduler {
}

void _scheduleTask() {
if (_pendingTaskCompleter != null) return;
// Don't schedule a task if there is already one pending or if the scheduler
// is disposed.
// It is possible that during disposal of a ProviderContainer, if a provider
// uses ref.keepAlive(), the keepAlive closure will try to schedule a task.
// In this case, we don't want to schedule a task as the container is already
// disposed.
if (_pendingTaskCompleter != null || _disposed) return;
_pendingTaskCompleter = Completer<void>();
vsync(_task);
}
@@ -122,6 +130,7 @@ class ProviderScheduler {
}

void dispose() {
_disposed = true;
_pendingTaskCompleter?.complete();
_pendingTaskCompleter = null;
}
2 changes: 1 addition & 1 deletion packages/riverpod/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@ name: riverpod
description: >
A simple way to access state from anywhere in your application while robust
and testable.
version: 2.4.8
version: 2.4.9
homepage: https://riverpod.dev
repository: https://github.com/rrousselGit/riverpod
issue_tracker: https://github.com/rrousselGit/riverpod/issues
Loading