riverpod icon indicating copy to clipboard operation
riverpod copied to clipboard

@rrousselGit @josh-burton I also encountered the same stack information, but I'm not sure if it's the same problem.

Open rrousselGit opened this issue 8 months ago • 1 comments

          @rrousselGit @josh-burton I also encountered the same stack information, but I'm not sure if it's the same problem.

image

This is the smallest reproducible sample:

void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const SafeArea(child: MyHomePage()),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  var value1 = "123";

  var value2 = "321";

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Row(
        children: [
          Expanded(
            child: TestWidget.keyed(
              value: value2,
            ),
          ),
          Expanded(
            child: TestWidget.keyed(
              value: value1,
            ),
          ),
        ],
      ),
      floatingActionButton: FloatingActionButton(
        child: const Icon(Icons.add),
        onPressed: () {
          setState(() {
            final tmp = value1;
            value1 = value2;
            value2 = tmp;
          });
        },
      ),
    );
  }
}

final provider = Provider<String>((ref) => throw UnimplementedError());

final asyncProvider =
    AutoDisposeAsyncNotifierProvider<Notifier, String>(() => Notifier());

class Notifier extends AutoDisposeAsyncNotifier<String> {
  @override
  FutureOr<String> build() {
    final data = ref.watch(provider);
    return Future.delayed(const Duration(seconds: 2), () => "$data async");
  }
}

class TestWidget extends StatelessWidget {
  TestWidget.keyed({required this.value}) : super(key: ValueKey(value));

  const TestWidget({super.key, required this.value});

  final String value;

  @override
  Widget build(BuildContext context) {
    return ProviderScope(
        overrides: [provider.overrideWithValue(value)],
        child: Consumer(
            builder: (BuildContext context, WidgetRef ref, Widget? child) {
          return ref.watch(asyncProvider).when(
              data: (Object data) {
                return Text(data.toString());
              },
              error: (Object error, StackTrace stackTrace) {
                return Text('Error: $error');
              },
              loading: () => const Center(child: CircularProgressIndicator()));
        }));
  }
}

Clicking the button twice will reappear.

I found two key points in this example:

  1. It can be reproduced using TestWidget.keyed(), but not TestWidget(), And TestWidget cannot be at the same children level
  2. asyncProvider must be AutoDispose

Originally posted by @hcanyz in https://github.com/rrousselGit/riverpod/issues/2022#issuecomment-1783770010

rrousselGit avatar Oct 31 '23 10:10 rrousselGit