riverpod icon indicating copy to clipboard operation
riverpod copied to clipboard

A possibility to dispose the root container

Open AhmedLSayed9 opened this issue 1 year ago • 5 comments

When using a parent container for the root ProviderScope, it will not be disposed if we call runApp again with a different parent.

Using the parent here is necessary for calling some async operations before running the app.

I think not auto-disposing the parent is reasonable, but is there another way to dispose the root container without declaring it globally?

I'm looking for something like:

ProviderScope.containerOf(context, rootContainer: true);

Example:

import 'dart:async';

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

Future<void> restartApp(BuildContext context) async {
  scheduleMicrotask(() {
    main();
    print("app restarted");
  });
}

void main() {
  final container = ProviderContainer();
  runApp(
    ProviderScope(
      key: UniqueKey(),
      parent: container,
      child: const TestApp(),
    ),
  );
}

class TestApp extends ConsumerWidget {
  const TestApp({
    super.key,
  });

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return const MaterialApp(
      title: 'App',
      home: HomeScreen(),
    );
  }
}

class HomeScreen extends ConsumerWidget {
  const HomeScreen({
    super.key,
  });

  @override
  Widget build(BuildContext context, ref) {
    return Scaffold(
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            Navigator.of(context).push(MaterialPageRoute(builder: (context) => const Page2()));
          },
          child: const Text('Go to Page2'),
        ),
      ),
    );
  }
}

class Page2 extends ConsumerWidget {
  const Page2({super.key});

  @override
  Widget build(BuildContext context, ref) {
    ref.watch(testProvider);
    return Scaffold(
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            restartApp(context);
          },
          child: const Text("Restart"),
        ),
      ),
    );
  }
}

final testProvider = StreamProvider<String>(
  (ref) async* {
    print('init');
    final timer = Timer.periodic(const Duration(seconds: 1), (timer) {
      print(ref.hashCode);
    });
    ref.onDispose(() {
      print('dispose');
      timer.cancel();
    });
    yield "";
  },
);

AhmedLSayed9 avatar Jan 18 '24 02:01 AhmedLSayed9

Using the parent here is necessary for calling some async operations before running the app.

No it isn't. No docs recommend putting init logic in the main. Instead it is recommended to use a ConsumerWidget at the root

I'm looking for something like:

ProviderScope.containerOf(context, rootContainer: true);

I don't see the relationship between this and disposing the root container. And this snippet isn't present in your example

So at the moment I'm not sure what you're requesting. The example you gave works today.

rrousselGit avatar Jan 18 '24 05:01 rrousselGit

No it isn't. No docs recommend putting init logic in the main. Instead it is recommended to use a ConsumerWidget at the root

I get that and I actually have a ConsumerWidget that act like a custom splash screen, but that screen still needs some information like the current locale/theme of the user which needs to be warmed-up during the native splash.

I don't see the relationship between this and disposing the root container. And this snippet isn't present in your example

So at the moment I'm not sure what you're requesting. The example you gave works today.

The example I gave is broken, with each restart the previous parent container won't be disposed.

AhmedLSayed9 avatar Jan 18 '24 12:01 AhmedLSayed9

I don't see the relationship between this and disposing the root container.

I'd be able to do the following at my restartApp method:

final rootContainer = ProviderScope.containerOf(context, rootContainer: true);
rootContainer.dispose();

AhmedLSayed9 avatar Jan 18 '24 12:01 AhmedLSayed9

The example I gave is broken, with each restart the previous parent container won't be disposed.

Keep a reference to it and dispose it then?

rrousselGit avatar Jan 18 '24 16:01 rrousselGit

That's what i'm doing currently. I was looking for a better and direct approach same as the rootNavigator of Navigator class. I think this has a low priority.

AhmedLSayed9 avatar Jan 18 '24 17:01 AhmedLSayed9

I don't think I'll add such an API. It's too niche and you can already work around this on your own.

rrousselGit avatar Mar 01 '24 11:03 rrousselGit