Search code examples
flutterdartstateflutter-navigation

Unable to access Provider in new page route Widget


I am unable to access the Provider in a Widget that I pushed onto the current Navigator:

import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:provider/provider.dart';


void main() => runApp(MyApp());

class MyModel with ChangeNotifier {
  String a = 'Test1';
  String b = 'Test2';
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {    

    return MaterialApp(
        title: 'Flutter Demo',
        home: ChangeNotifierProvider(
            create: (context) => MyModel(),
            child: MyHomePage()
        )
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key}) : super(key: key);

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  @override
  Widget build(BuildContext context) {    

    return Consumer<MyModel>(
        builder: (context, myModel, child) =>
            Scaffold(
              appBar: AppBar(
                title: Text(myModel.a),
              ),
              floatingActionButton: FloatingActionButton(
                onPressed: () =>
                    Navigator.of(context).push(
                        PageRouteBuilder(
                            pageBuilder: (context, animation, secondaryAnimation) => Page2(),
                        ),
                    ),
                tooltip: 'Press',
                child: Icon(Icons.add),
              ),
            )
    );
  }
}

class Page2 extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    var myModel = Provider.of<MyModel>(context); // A

    return Scaffold(
              appBar: AppBar(
                title: Text(myModel.b),
              ),
            );
  }
}

I get this error:

The following ProviderNotFoundException was thrown building Page2(dirty):
Error: Could not find the correct Provider<MyModel> above this Navigator Widget

The issue seems to be that the BuildContext object in the Page2 widget is not the same BuildContext that's associated with the Provider. If I pass a reference of original context to Page2 and use that at point (A), everything works, but this doesn't seem to be a good way of solving this problem.

I tried the solution here, by using Navigator.of(context, rootNavigator: true).context as the context inside the build method of Page2, but I still get the same exception.


Solution

  • Yo must pass provider in root widget such that you can access from any where when you navigate to another page the model is not available so you must pass the provider to the parent of MaterialApp as

     import 'package:flutter/material.dart';
    import 'package:flutter/foundation.dart';
    import 'package:provider/provider.dart';
    
    void main() => runApp(MyApp());
    
    class MyModel with ChangeNotifier {
      String a = 'Test1';
      String b = 'Test2';
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return ChangeNotifierProvider(
          create: (context) => MyModel(),
          child: MaterialApp(title: 'Flutter Demo', home: MyHomePage()),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      MyHomePage({Key key}) : super(key: key);
    
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      @override
      Widget build(BuildContext context) {
        return Consumer<MyModel>(
            builder: (context2, myModel, child) => Scaffold(
                  appBar: AppBar(
                    title: Text(myModel.a),
                  ),
                  floatingActionButton: FloatingActionButton(
                    onPressed: () => Navigator.of(context).push(
                      PageRouteBuilder(
                        pageBuilder: (context, animation, secondaryAnimation) =>
                            Page2(),
                      ),
                    ),
                    tooltip: 'Press',
                    child: Icon(Icons.add),
                  ),
                ));
      }
    }
    
    class Page2 extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        var myModel = Provider.of<MyModel>(context); // A
    
        return Scaffold(
          appBar: AppBar(
            title: Text(myModel.b),
          ),
        );
      }
    }