StreamBuilder 子更新在导航后不呈现

StreamBuilder child update not rendering after navigation

我正在使用 flutter 的 StreamBuilder 来决定向用户显示哪个“根”页面。现在基本上有 2 种可能性 - 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'),
    ));
  }
}

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

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

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)

请尝试此方法,它应该有效。