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

标签 dart flutter inherited-widget

当我在应用加载时尝试从本地存储读取数据时遇到了 flutter 问题。

我有一个继承的小部件,其中包含当前用户的身份验证信息。当应用程序加载时,我想查看 session token 的本地存储。如果 session token 存在,我想使用此信息更新继承的小部件。

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

我遇到的问题是我无法从依赖于继承小部件(我的路由器小部件)的小部件的 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.

路由器小部件(根)

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,
          );
        });
  }
}

检查身份验证并更新自身的继承的 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));
  }

主要

void main() => runApp(
  EnvironmentContainer(
    baseUrl: DEV_API_BASE_URL,
    child: AuthContainer(
      child: Root()
    )
  )
);

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

最佳答案

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

例子:

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

另一种方法是使用 SchedulerBindinginitState 中安排数据获取。您可以找到文档 here

SchedulerBinding.instance.addPostFrameCallback((_) {
  // your login goes here
});

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

希望这会有所帮助!

关于dart - 正确 Flutter 小部件序列以在应用加载时提取数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55073225/

相关文章:

dart - Flutter:从其他文件提供“映射到路线”选项

flutter - 如何在花括号前后添加空格?

flutter - 使用InheritedWidget在子级中触发触发器 Action

android - Flutter 中的 HTTP 请求

arrays - Flutter 解析来自本地化 JSON 文件的数组

crud - Dart 可以用于基本的 CRUD Web 应用程序吗?

flutter - 如何扩展 flutter 小部件并为其内部值设置默认值?

flutter - 为什么 firebase 消息传递不起作用,尽管我对 android x 进行了修改

performance - 为什么findAncestorWidgetOfExactType为O(N)而DependOnInheritedWidgetOfExactType为O(1)

dart - 你如何在 Flutter 中创建服务/提供者?