-1

这是我正在制作的应用程序的登录代码。我想更新在发布请求后获得的 parent_inherit(Inherited Widget) 中的令牌。但是我无法理解如何在没有该构建方法或 parent_inherit 小部件的情况下显式更新 Inherited 小部件变量的值。我想改变继承小部件(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'];

}

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

主要.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(),
        },
      ),
    );
  }
}

也欢迎其他建议...

4

1 回答 1

1

更新 an 的一种方法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并不是那么容易,所有这些都是针对单个值的。

也许考虑其他状态管理解决方案,我没有任何特别的建议,但颤振文档在这里列出了最常用的解决方案。

于 2021-02-10T06:35:24.123 回答