How to access data of an InheritedWidget with pushed routes?

Viewed 32

So I have an InheritedWidget which holds a token.

class TokenHolder extends InheritedWidget {
  final String token;

  const TokenHolder({@required this.token, @required Widget child})
      : assert(child != null),
        super(child: child);

  @override
  bool updateShouldNotify(TokenHolder oldWidget) => oldWidget.token != token;

  static TokenHolder of(BuildContext context) {
    return context.dependOnInheritedWidgetOfExactType<TokenHolder>();
  }
}

Then somewhere high up in my app, I have used it to display MyScreen

...
builder: (context) {
  ...
  return TokenHolder(
     token: token,
     child: MyScreen(),
  );
}

MyScreen works as expected. It can get the TokenHolder´s token correctly.

class MyScreen extends StatefulWidget {
  @override
  _MYyScreenState createState() => _MYyScreenState ();
}

class _MYyScreenState extends State<MyScreen > {
  @override
  Widget build(BuildContext context) {
    String token = TokenHolder.of(context).token; // This works

    return RaisedButton(
      onPressed: () {
        Navigator.push(context, builder: (context) => PushedScreen());
      },
      child: Text(token) // This works
    );
  }
}

However, PushedScreen seems to return null when we call TokenHolder.of(context). Why is this? Why cannot the TokenHolder be found?

class PushedScreen extends StatefulWidget {
  @override
  _PushedScreenState createState() => _PushedScreenState ();
}

class _PushedScreenState extends State<PushedScreen > {
  @override
  Widget build(BuildContext context) {
    String token = TokenHolder.of(context).token; // DOES NOT WORK -> null.token

    return Text(token);
  }
}
1 Answers

Instead of accessing the token using "TokenHolder.of(context).token", you could pass the token as an argument when you push the route. (I don't know if it's required to use pushNamed, but that's what I use)

Navigator.pushNamed(
    context,
    '/pushedScreen', 
    arguments: token
);

Then to get the token in PushedScreen either use:

MaterialApp(
    onGenerateRoute: (settings) { 
        //only needed if their are multiple screens
        if (settings.name == '/pushedScreen') {
            String token = settings.arguments;
        } 
    }
    
)

You can also try (within pushedScreen)

@override
Widget build(BuildContext context) {
    String token = ModalRoute.of(context).settings.arguments;
}

To use pushNamed:

MaterialApp(
    ...
    initialRoute: '/',
    routes {
        '/': (context) => ARoute(),
        '/pushedScreen': (context) => PushedScreen(),
    }
)
Related