更新继承小部件的变量值

问题描述

这是我正在制作的应用程序的登录代码。我想更新我在发布请求后得到的 parent_inherit(Inherited Widget) 中的令牌。 Inherited widget(parent_inherit) 中的令牌值。

Future<void> attemptLogIn(String username,String password,BuildContext context) async {
  String parentToken= parent_inherit.of(context);
  SharedPreferences prefs = await SharedPreferences.getInstance();
  print("$username $password");
  final http.Response res = await http.post(
      "..............the route.............",headers: <String,String>{
        'Content-Type': 'application/json; charset=UTF-8',},body: jsonEncode(<String,String>{
        "email": username,"password": password
      }),);
  if(res.statusCode == 200) {
    prefs.setString('jwt',res.body);
    var value=prefs.getString('jwt');
    Map<String,dynamic> valueMap=jsonDecode(value);
    TokenClass token=TokenClass.fromJson(valueMap);


    parentToken=token.token;// I was trying something like this,but it seems to not work


    Navigator.of(context).pushNamed('/home');
  }
  else{
    return _showMyDialoglogin(context,res.statusCode);
  }
}

另外,在上面的文件中,当我在上面声明 parentToken 并使用它时,它仍然显示上面声明的 parentToken 没有被使用。当我将鼠标悬停在它上面时它也会显示警告。为什么会这样?

parent_inherit.dart

class parent_inherit extends InheritedWidget {
  final String token;

  const parent_inherit({
    Key key,@required this.token,Widget child})
      :super(key:key,child: child);

  @override
  bool updateShouldNotify(parent_inherit oldWidget) =>true;

  static String of(BuildContext context) => context.dependOnInheritedWidgetofExactType<parent_inherit>().token;
}

TokenClass.dart

class TokenClass{
  final String token;

  TokenClass(this.token);

  TokenClass.fromJson(Map<String,dynamic> json)
  : token=json['token'];

}

我的主要功能 - 在主要功能中,令牌值存在问题,无法正确更新和获取继承小部件内外的值。有时它也使用以前的令牌值。

main.dart

bool checkingKey;
String tokenName;
TokenClass token;

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  Paint.enableDithering = true;
  const defaultJson = '{}';
  var prefs = await SharedPreferences.getInstance();
  checkingKey = prefs.containsKey("jwt");
  

  tokenName=prefs.getString('jwt');
  
  Map<String,dynamic> valueMap = jsonDecode(tokenName??defaultJson);
  token=TokenClass.fromJson(valueMap);
 
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return parent_inherit(
      token: checkingKey==false?'':token.token,child: MaterialApp(
        home: AnnotatedRegion<systemUIOverlayStyle>(
          value: systemUIOverlayStyle(
            statusBarColor: Colors.transparent,),child: Scaffold(
            resizetoAvoidBottomInset: false,body: Container(
              color: Color(0xffccffcc),child: !checkingKey ? LoginPage() : mainPage(),routes: <String,WidgetBuilder>{
          '/home':(BuildContext context) => mainPage(),'/login':(BuildContext context) => LoginPage(),);
  }
}

也欢迎其他建议...

解决方法

更新 InheritedWidget 的一种方法是使用 Notification

首先,我们有我们的通知类:

class LoginNotification extends Notification {
  final TokenClass token;

  LoginNotification(this.token);
}

然后我们用通知侦听器包装 parent_inherit

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    return NotificationListener<LoginNotification>(
      onNotification: (loginNotification) {
        setState(() {
          token = loginNotification.token;
          checkingKey = true;
        });
        return true;
      },child: parent_inherit(
        token: checkingKey ? token.token : '',child: MaterialApp(
          home: AnnotatedRegion<SystemUiOverlayStyle>(
            value: SystemUiOverlayStyle(
              statusBarColor: Colors.transparent,),child: Scaffold(
              resizeToAvoidBottomInset: false,body: Container(
                color: Color(0xffccffcc),child: checkingKey ? MainPage() : LoginPage(),routes: <String,WidgetBuilder>{
            '/home': (BuildContext context) => MainPage(),'/login': (BuildContext context) => LoginPage(),},);
  }
}

attemptLogIn 方法中,你只需要发送一个通知:

Future<void> attemptLogIn(
    String username,String password,BuildContext context) async {
  SharedPreferences prefs = await SharedPreferences.getInstance();
  if (kDebugMode) print("$username $password");
  final http.Response res = await http.post(
    "..............the route.............",headers: <String,String>{
      'Content-Type': 'application/json; charset=UTF-8',body: jsonEncode(<String,String>{"email": username,"password": password}),);
  if (res.statusCode == 200) {
    // check if the login is valid first
    //...

    prefs.setString('jwt',res.body);
    var value = prefs.getString('jwt');
    Map<String,dynamic> valueMap = jsonDecode(value);
    TokenClass token = TokenClass.fromJson(valueMap);

    // send notification to a LoginNotification Listener
    LoginNotification(token).dispatch(context);

    Navigator.of(context).pushNamed('/home');
  } else {
    return _showMyDialoglogin(context,res.statusCode);
  }
}

如您所见,使用 InheretedWidget 并不容易,而且所有这些都是针对单个值的。

也许可以考虑其他状态管理解决方案,我没有任何特别的建议,但 Flutter 文档列出了最常用的解决方案 here