3

I have the below example which does refresh the data but does not give a spinner as expected. I tried using ref.listen to switch to async loading, i tried await in front of the call even though it didn't make sense.

I tried ref.refresh, ref.invalidate... Expected behaviour: Open app, see spinner, tap button, see spinner again before text changes. Actual behaviour: Open app, see spinner, tap button, text changes and no spinner shows. also see https://github.com/neiljaywarner/riverpod_watching_dep_no_spinner_sample I'm using flutter 3.0.5 and hooks_riverpod: ^2.0.0-dev.9.

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

void main() => runApp(ProviderScope(child: MyApp()));

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) => MaterialApp(title: 'Riverpod Spinner Demo',
      theme: ThemeData(primarySwatch: Colors.blue), home: MyHomePage());
}

class MyHomePage extends ConsumerWidget {

  @override
  Widget build(BuildContext context, WidgetRef ref) => Scaffold(
      appBar: AppBar(title: const Text('Riverpod Spinner Question'),),
      body: ref.watch(futureProvider).when(data: (data) => Column(
        children: [
          ElevatedButton(onPressed: () => ref.read(paramProvider.notifier).state = 'new value',
              child: const Text('pretend update')),
          Text(data)],
      ),
          error: (_,__) => const Text('something went wrong'),
          loading: () => const CircularProgressIndicator())
  );
}

final paramProvider = StateProvider((ref) => 'Initial value');

final futureProvider = FutureProvider.autoDispose<String>((ref) async {
  String parameter = ref.watch(paramProvider);
  return pretendApiCall(parameter);
});
Future<String> pretendApiCall(String parameter) async {
  await Future.delayed(const Duration(seconds: 3));
  return parameter;
}
nAndroid
  • 862
  • 1
  • 10
  • 25

4 Answers4

4

Ah.

var asyncValue = ref.watch(futureProvider);
return Scaffold(
  appBar: AppBar(title: const Text('Riverpod Spinner Question'),),
  body: asyncValue.when(data: (data) {
    if (asyncValue.isRefreshing) return const CircularProgressIndicator();
    return Column(
    children: [
      ElevatedButton(onPressed: () => ref.read(paramProvider.notifier).state = 'new value',
          child: const Text('pretend update')),
      Text(data)],
  );
  },
nAndroid
  • 862
  • 1
  • 10
  • 25
  • Yeah, it's almost like we now have 4 states, but .when provides only 3 legs. Time for an exetension wrapper on AsyncValue? :) – Randal Schwartz Oct 06 '22 at 16:02
  • @RandalSchwartz i like that idea. I use .defaultWhen anyway to have a centeered loading spinner and default Error message – nAndroid Oct 08 '22 at 03:35
2

I think you're seeing this breaking changed behavior:

Breaking After a provider has emitted an AsyncValue.data or AsyncValue.error, that provider will no longer emit an AsyncValue.loading. Instead, it will re-emit the latest value, but with the property AsyncValue.isRefreshing to true.

So the behavior you describe is by design.

Randal Schwartz
  • 39,428
  • 4
  • 43
  • 70
  • This actually does sound familiar -from the release notes or Andrea BIzzotti or both. That does however, not jog my memory yet on how to "fix" it. :) – nAndroid Sep 03 '22 at 22:11
1

Try to upgrade your Flutter 3.3.0 And using hooks_riverpod: ^1.0.4

enter image description here

Md. Yeasin Sheikh
  • 54,221
  • 7
  • 29
  • 56
1

ah - the real answer from Remi himself https://github.com/rrousselGit/riverpod/discussions/1600 "This behavior has changed on the master branch

Simply wait for a release and your problem should disappear"

nAndroid
  • 862
  • 1
  • 10
  • 25