更正Flutter小部件序列以在应用加载时提取数据

Tem*_*Fix 9 dart flutter inherited-widget

当我尝试在应用加载时从本地存储读取数据时,出现了抖动问题。

我有一个继承的小部件,其中包含当前用户的身份验证信息。应用加载时,我想查看会话令牌的本地存储。如果会话令牌存在,我想用此信息更新继承的窗口小部件。

我的屏幕是动态的。如果知道用户已通过身份验证,则将他们带到请求的屏幕,否则将他们带到注册屏幕。

我遇到的问题是我无法initState()通过依赖于继承的窗口小部件(我的路由器窗口小部件)的窗口小部件中的方法更新继承的窗口小部件的状态。

应用加载并更新继承的小部件时,如何从本地存储中读取信息?

运行应用程序时出错:

flutter: ??? EXCEPTION CAUGHT BY WIDGETS LIBRARY ????????????????????????????????????????????????????????????
flutter: The following assertion was thrown building _InheritedAuthContainer:
flutter: inheritFromWidgetOfExactType(_InheritedAuthContainer) or inheritFromElement() was called before
flutter: RootState.initState() completed.
flutter: When an inherited widget changes, for example if the value of Theme.of() changes, its dependent
flutter: widgets are rebuilt. If the dependent widget's reference to the inherited widget is in a constructor
flutter: or an initState() method, then the rebuilt dependent widget will not reflect the changes in the
flutter: inherited widget.
flutter: Typically references to inherited widgets should occur in widget build() methods. Alternatively,
flutter: initialization based on inherited widgets can be placed in the didChangeDependencies method, which
flutter: is called after initState and whenever the dependencies change thereafter.
Run Code Online (Sandbox Code Playgroud)

路由器小部件(根)

class Root extends StatefulWidget {
  @override
  State createState() => RootState();
}

class RootState extends State<Root> {
  static Map<String, Widget> routeTable = {Constants.HOME: Home()};
  bool loaded = false;
  bool authenticated = false;

  @override
  void initState() {
    super.initState();
    if (!loaded) {
      AuthContainerState data = AuthContainer.of(context);
      data.isAuthenticated().then((authenticated) {
        setState(() {
          authenticated = authenticated;
          loaded = true;
        });
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        initialRoute: '/',
        onGenerateRoute: (routeSettings) {
          WidgetBuilder screen;
          if (loaded) {
            if (authenticated) {
              screen = (context) => SafeArea(
                  child: Material(
                      type: MaterialType.transparency,
                      child: routeTable[routeSettings.name]));
            } else {
              screen = (conext) => SafeArea(
                  child: Material(
                      type: MaterialType.transparency, child: Register()));
            }
          } else {
            screen = (context) => new Container();
          }
          return new MaterialPageRoute(
            builder: screen,
            settings: routeSettings,
          );
        });
  }
}
Run Code Online (Sandbox Code Playgroud)

继承的Widget方法,用于检查身份验证并更新自身,从而触发路由器小部件的重新渲染

Future<bool> isAuthenticated() async {
    if (user == null) {
      final storage = new FlutterSecureStorage();
      List results = await Future.wait([
        storage.read(key: 'idToken'),
        storage.read(key: 'accessToken'), 
        storage.read(key: 'refreshToken'),
        storage.read(key: 'firstName'),
        storage.read(key: 'lastName'),
        storage.read(key: 'email')
      ]);
      if (results != null && results[0] != null && results[1] != null && results[2] != null) {
        //triggers a set state on this widget
        updateUserInfo(
          identityToken: results[0], 
          accessToken: results[1], 
          refreshToken: results[2],
          firstName: results[3],
          lastName: results[4],
          email: results[5]
        );
      }
    }
    return user != null && (JWT.isActive(user.identityToken) || JWT.isActive(user.refreshToken));
  }
Run Code Online (Sandbox Code Playgroud)

主要

void main() => runApp(
  EnvironmentContainer(
    baseUrl: DEV_API_BASE_URL,
    child: AuthContainer(
      child: Root()
    )
  )
);
Run Code Online (Sandbox Code Playgroud)

检查应用程序加载时本地存储并更新包含此信息的继承窗口小部件的正确方法是什么?

Hem*_*Raj 7

实际上,您无法InheritedWidget从initState方法访问。而是尝试从访问它didChangeDependencies。

例:

@override
void didChangeDependencies() {
  super.didChangeDependencies();
  if (!loaded) {
    AuthContainerState data = AuthContainer.of(context);
    data.isAuthenticated().then((authenticated) {
      setState(() {
        authenticated = authenticated;
        loaded = true;
      });
    });
  }
}
Run Code Online (Sandbox Code Playgroud)

另一种方式是安排数据中提取initState与SchedulerBinding。您可以在这里找到文档

SchedulerBinding.instance.addPostFrameCallback((_) {
  // your login goes here
});
Run Code Online (Sandbox Code Playgroud)

注意:请记住,didChangeDependencies只要任何父项的状态或依赖项InheritedWidget发生变化,都会调用。请在这里查看文档。

希望这可以帮助!