更新继承的小部件变量的值

Update value of variable of inherited widget

这是我正在制作的应用程序的登录代码。我想更新 parent_inherit(Inherited Widget) 中的令牌,这是我在发布 request.But 后得到的 我无法理解如何在没有该构建方法的情况下显式更新 Inherited widget 变量的值或 parent_inherit widget.I 想要更改 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 不是 used.It 当我将鼠标悬停在 it.Why 上时也会显示警告,所以?

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'];

}

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

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:

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