【问题标题】:StreamBuilder child update not rendering after navigation导航后 StreamBuilder 子更新不呈现
【发布时间】:2021-05-09 12:59:25
【问题描述】:

我正在使用 Flutter 的 StreamBuilder 来决定向用户显示哪个“根”页面。现在基本上有两种可能性 - LoginPageHomePage。我的应用的主要构建方法如下所示:

  Widget build(BuildContext context) => StreamProvider.value(
      initialData: CurrentUser.initial,
      value: AuthService().user,
      child: Consumer<CurrentUser>(
          builder: (context, currentUser, _) => MaterialApp(
              home: currentUser.isInitialValue
                  ? Scaffold(
                      body: Center(
                        child: CircularProgressIndicator(),
                      ),
                    )
                  : currentUser.user != null
                      ? MultiProvider(providers: [
                          Provider<User>.value(value: currentUser.user),
                          // NOTE: Any other user-bound providers here can be added here
                        ], child: HomePage())
                      : LoginPage())));

登录页面的相关部分是它为您提供了两个选项:

  1. “你是新用户吗” - 注册
  2. “你回来了吗” - 登录

当您单击其中一个按钮时,您会通过导航器以特定模式进入表单:

Navigator.push(
                                context,
                                CupertinoPageRoute(
                                  builder: (context) => LoginPage(
                                    mode: LoginPageMode.signUp,
                                  ),
                                ))

成功登录或注册后,流会更新并呈现HomePage。我知道这一点是因为我在构建方法中有一个打印语句("Building HomePage"):

class HomePage extends StatelessWidget {
  const HomePage({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    print('Building HomePage');
    return Scaffold(
        body: Container(
      alignment: Alignment.center,
      child: Text('HOME'),
    ));
  }
}

但是,屏幕实际上并没有改变。屏幕保留在登录页面上。我认为我可以很好地管理流,因为如果我不是,渲染方法将永远不会被击中。我看到了一个类似的问题here,但似乎他们没有正确管理流。我怎样才能看到渲染方法命中,但屏幕保持不变?我使用 Flutter 已经有一段时间了,以前从未见过这种情况。

我认为这与导航有关,因为如果我删除用户选择“登录”或“注册”的步骤,我只是将他们发送到登录页面,问题就会消失。这就像HomePage 正在被导航到的页面下构建。

【问题讨论】:

  • key: UniqueKey(), 添加到MaterialApp
  • 这确实有帮助,我一直在搞乱 MaterialApp 键。然而,它确实会导致一个奇怪的临时状态,它会在转到 HomePage 之前返回 LoginPage 几秒钟。但是,如果我手动构建密钥key = user == null ? 'user-null' : '${user.id}',它会起作用,并且不会发生这种奇怪的中间状态。一种感觉不对,另一种感觉很不自然。为什么 build 方法执行时没有 Flutter 渲染?我认为键是用于确定是否调用 build,而不是用于确定是否绘制屏幕......
  • 我不知道它是否是 MaterialApp 小部件的错误或功能 - 我需要检查官方文档和源代码

标签: flutter stream-builder


【解决方案1】:

1。说明

这种行为的原因是您使用根导航器在应用程序根级别推送LoginPage 路由。这是小部件树在推送后显示小部件关系:

App
  |
  |-- StreamBuilder
  |      |--LoginPage()
  |
  |-- LoginPage(mode: LoginPageMode.signUp)

因此,当您的 StreamBuilder 更改数据时,树将变为:

App
  |
  |-- StreamBuilder
  |      |--HomePage()    // <--- CHANGED
  |
  |-- LoginPage(mode: LoginPageMode.signUp)

这就是为什么您仍然会看到 LoginPage 并同时呈现 HomePage 的原因。 HomePage 只是在“下方”LoginPage

2。解决方案

解决方法是使用嵌套导航器:


Widget build(BuildContext context) => StreamProvider.value(
      initialData: CurrentUser.initial,
      value: AuthService().user,
      child: Consumer<CurrentUser>(
          builder: (context, currentUser, _) => MaterialApp(
              home: currentUser.isInitialValue
                  ? Scaffold(
                      body: Center(
                        child: CircularProgressIndicator(),
                      ),
                    )
                  : currentUser.user != null
                      ? MultiProvider(providers: [
                          Provider<User>.value(value: currentUser.user),
                          // NOTE: Any other user-bound providers here can be added here
                        ], child: HomePage())
                      : Navigator(                //  <--- HERE
                          onGenerateRoute: (settings) {
                            return CupertinoPageRoute(
                              builder: (context) => LoginPage(),
                            );
                          },
                        )));

...

在这种情况下,当您在 LoginPage 中调用 Navigator.push(context, ...) 时,您的小部件树将如下所示:

App
  |
  |-- StreamBuilder
         |-- Navigator()
              |-- LoginPage()
              |-- LoginPage(mode: LoginPageMode.signUp)

请尝试这种方法,它应该可以工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-07
    • 1970-01-01
    • 1970-01-01
    • 2019-04-24
    • 1970-01-01
    • 2013-10-13
    相关资源
    最近更新 更多