0

i'm new to use Provider integrate with go_router in Flutter follow by MVVM pattern. Problem happen when my Provider class needs initial value in constructor. Let's say we have 2 screens with its view models: Screen1 with ViewModel1 and Screen2 with ViewModel2. The approach we normally see is that:

  runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (context) => ViewModel1()),
        ChangeNotifierProvider(create: (context) => ViewModel2()),
      ],
      child: const MyApp(),
    ),
  );

But in my case, ViewModel2 is a PDP screen and it needs an ID parameter (to call api get detail) which passed from Screen1, because of that, we can not init 2 Providers at the root of the app like above.

I've tried to refactor the structure a bit, instead of create Providers at the root of app, i create Provider (view model) when screen is open by creating a base class, like this:

abstract class BaseScreen<Vm extends BaseViewModel> extends StatelessWidget {
  Vm createViewModel();

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () => FocusManager.instance.primaryFocus?.unfocus(),
      child: ChangeNotifierProvider(
        create: (_) => createViewModel(),
        child: ...
      ),
    );
  }
}

And 2 screens will extend this BaseScreen and 2 view models will extend BaseViewModel, like this:

class Screen2 extends BaseView<ViewModel2> {
  final int id;

  @override
  Screen2 createViewModel() => ViewModel2(id);

  ...

It's works fine at the beginning. But the issue happen, i cannot access the previos Provider in ViewModel2 by using context.read<ViewModel1>(), it throw error cannot find Provider in widget tree. So i've checked the widget tree, (which using go_router for navigation), and it's look similar to this: Widget Tree Image The outer screen is not wrap it's sub routes, all the screen is the same level, children of root, so that context.read<ViewModel1>() cannot find the previous Provider.

You guys have any solutions for this problem? Thank you in advanced.

Milan Surelia
  • 884
  • 1
  • 8
  • 18

1 Answers1

0

I had the same issue. My solution was to get data from current app state and use it directly in the router like so:

GoRoute(
        path: 'touch-calibration',
        name: 'touch_calibration',
        builder: (context, state) => TouchCalibrationScreen(isFirstRun: state.queryParams['firstRun'] == 'true'),
      ),

Then to push route use context.pushNamed().

Piotr
  • 545
  • 4
  • 13