2

I want to declare a user object, that I will instantiate with an http request, and I want it to be global. How can I do it? With a Singleton? But how can I make this class also a Singleton? Or is there another way? That is what I've done so far:

class User{
String username;
String password;
  int id;

User({this.username, this.id});

  factory User.fromJson(Map<String, dynamic> json){
    return User(
      username: json['name'],
      id: json['id']
    );
  }

}

and then:

var user = await login(username, password, context);
4
  • 2
    You really don't want Singletons in your app. I think what you really want is a way to access a User object that is shared near the top of your Widget tree. You could use something like scoped_model. This way you can define your User object as a Model, complete with methods to perform login, wrap the ScopedModel<User> around your root and use ScopedModelDescendant<User> where ever you have login buttons or User name text labels. Commented Aug 29, 2018 at 13:12
  • Probably a stupid question, but if I use Navigator.of(context).pushNamedAndRemoveUntil, does the scopedModelDescendant find the user object or won't? Commented Aug 29, 2018 at 14:18
  • Navigator.of is going to search up the widget hierarchy until it finds the closest NavigatorState. If you only provide navigation using the WidgetsApp or MaterialApp, then that's the widget it will find. This means that as long as you wrap your App with the ScopedModel<User> then the scoped model descendants will be able to find it, even if you change routes. Commented Aug 29, 2018 at 14:28
  • Thank you so much! Commented Aug 29, 2018 at 14:35

1 Answer 1

1

In flutter, you should not make singletons. Instead, you should store it into a widget that exposes these data to all of its descendants. Usually InheritedWidget

The reason being, with such architecture all the descendants are automatically aware of any change made to your "singleton".

A typical example would be the following:

@immutable
class User {
  final String name;

  User({this.name});
}

class Authentificator extends StatefulWidget {
  static User currentUser(BuildContext context) {
    final _AuthentificatorScope scope = context.inheritFromWidgetOfExactType(_AuthentificatorScope);
    return scope.user;
  }

  final Widget child;

  Authentificator({this.child, Key key}): super(key: key);

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

class _AuthentificatorState extends State<Authentificator> {
  @override
  Widget build(BuildContext context) {
    return _AuthentificatorScope(
      child: widget.child,
    );
  }
}

class _AuthentificatorScope extends InheritedWidget {
  final User user;

  _AuthentificatorScope({this.user, Widget child, Key key}) : super(child: child, key: key);

  @override
  bool updateShouldNotify(_AuthentificatorScope oldWidget) {
    return user != oldWidget.user;
  }
}

which you have to instantiate like this:

new MaterialApp(
  title: 'Flutter Demo',
  builder: (context, child) {
    return Authentificator(
      child: child,
    );
  },
  home: Home(),
);

and then use inside your pages like this:

@override
Widget build(BuildContext context) {
  User user = Authentificator.currentUser(context);
  ...
}
Sign up to request clarification or add additional context in comments.

10 Comments

Probably a stupid question, but if I use Navigator.of(context).pushNamedAndRemoveUntil, would it work the same?
Not sure what you meant by that
for example, in the scoped model, it goes over the Widget tree. I don't know if remove will delete these relationships or not. Probably not, but just asking
No the navigator stack and the widget tree are unrelated
Thank you so much!
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.