Flutter web,授权后更新navbar

Flutter web, update navbar after authorization

我正在尝试使用 Flutter 创建 Web 应用程序,但我有一个问题。通过授权后,我需要更改导航栏中的“登录”按钮,据我了解,我需要更改按钮文本并在我的导航栏中调用 setState,但在我的实现中抛出异常。

AuthPage.dart

import 'package:flutter/material.dart';
import 'package:um/pages/home/app_color.dart';
import 'package:um/scripts/api_client.dart';
import 'package:um/scripts/locator.dart';

import 'NavBarDesktop.dart';

class AuthorizationPageDesktop extends StatefulWidget {
  AuthorizationPageDesktop({Key key}) : super(key: key);

  @override
  _AuthorizationPageDesktopState createState() =>
      _AuthorizationPageDesktopState();
}

class _AuthorizationPageDesktopState extends State<AuthorizationPageDesktop> {
  TextEditingController _emailController = TextEditingController();
  TextEditingController _passwordController = TextEditingController();
  bool rememberMe = false;
  ApiClient apiClient = ApiClient.getInstance();
  ScrollController _scrollController = ScrollController();
  PageController _pageController = PageController();

  @override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
        child: Container(
            child: Padding(
      padding: EdgeInsets.only(top: 150, left: 0, right: 0),
      child: Column(
        children: <Widget>[
          Text(
            'Авторизация',
            style: TextStyle(
                fontWeight: FontWeight.w600,
                fontSize: 28,
                color: textPrimaryColor),
          ),
          SizedBox(
            height: 40,
          ),
          _input(Icon(Icons.mail), 'Email', _emailController, false, 15),
          SizedBox(
            height: 15,
          ),
          _input(Icon(Icons.lock), 'Password', _passwordController, true, 15),
          SizedBox(
            height: 5,
          ),
          Container(
              padding: EdgeInsets.only(left: 20, right: 20),
              width: 460,
              child: Theme(
                  data: ThemeData(
                      splashColor: Colors.transparent,
                      highlightColor: Colors.transparent,
                      hoverColor: Colors.transparent),
                  child: CheckboxListTile(
                    title: Text(
                      'Запомнить меня',
                      style: TextStyle(color: textPrimaryColor),
                    ),
                    value: rememberMe,
                    onChanged: (bool value) {
                      setState(() {
                        rememberMe = value;
                      });
                    },
                  ))),
          SizedBox(
            height: 5,
          ),
          _button('Войти', auth, 15),
          SizedBox(
            height: 15,
          ),
          Container(
            width: 460,
            child: Align(
                alignment: Alignment.bottomCenter,
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    Text(
                      'Пройдите ',
                      style: TextStyle(color: Colors.white, fontSize: 12),
                    ),
                    Text(
                      'регистрацию, ',
                      style: TextStyle(color: linkColor, fontSize: 12),
                    ),
                    Text(
                      'если вы этого еще не сделали',
                      style: TextStyle(color: Colors.white, fontSize: 12),
                    ),
                  ],
                )),
          ),
          SizedBox(height: 50),
        ],
      ),
    )));
  }

  Widget _input(Icon icon, String hint, TextEditingController controller,
      bool obscure, double borderRadius) {
    return Container(
      width: 460,
      height: 50,
      padding: EdgeInsets.only(left: 20, right: 20),
      child: TextField(
        controller: controller,
        obscureText: obscure,
        style: TextStyle(fontSize: 16, color: Colors.white),
        decoration: InputDecoration(
            border: OutlineInputBorder(),
            isDense: true, // Added this
            contentPadding: EdgeInsets.all(8), //

            hintStyle: TextStyle(
                fontWeight: FontWeight.bold, fontSize: 16, color: Colors.white),
            hintText: hint,
            focusedBorder: OutlineInputBorder(
                borderRadius: BorderRadius.circular(borderRadius),
                borderSide: BorderSide(color: Colors.white, width: 2)),
            enabledBorder: OutlineInputBorder(
                borderRadius: BorderRadius.circular(borderRadius),
                borderSide: BorderSide(color: Colors.white54, width: 1)),
            prefixIcon: Padding(
              padding: EdgeInsets.only(left: 10, right: 10),
              child: IconTheme(
                data: IconThemeData(color: Colors.white),
                child: icon,
              ),
            )),
      ),
    );
  }

  Widget _button(String label, void func(), double borderRadius) {
    return Container(
        width: 460,
        padding: EdgeInsets.only(left: 20, right: 20),
        child: RaisedButton(
          onPressed: () {
            apiClient
                .authorization(_emailController.text, _passwordController.text)
                .then((value) {
              func();
            });
          },
          highlightColor: Theme.of(context).primaryColor,
          color: buttonPrimaryColor,
          child: Text('Войти',
              style: TextStyle(
                  fontWeight: FontWeight.bold,
                  color: textPrimaryColor,
                  fontSize: 16)),
          shape: RoundedRectangleBorder(
              borderRadius: BorderRadius.circular(borderRadius)),
        ));
  }

  void auth() {
    var state = navBar<NavBarDesktop>().navBarState;
    state.update();
  }
}

NavBar.dart

import 'package:flutter/material.dart';
import 'package:um/Widgets/Desktop/AuthPageDesktop.dart';
import 'package:um/Widgets/Desktop/HomePageDesktop.dart';
import 'package:um/Widgets/NavBarItem.dart';
import 'package:um/layout_template/layout_template.dart';
import 'package:um/pages/home/app_color.dart';
import 'package:um/scripts/api_client.dart';
import 'package:um/scripts/locator.dart';

class NavBarDesktop extends StatefulWidget {
  NavBarDesktop({Key key}) : super(key: key);

  GlobalKey<_NavBarDesktopState> navBarDesktop =
      GlobalKey<_NavBarDesktopState>();

  _NavBarDesktopState navBarState = new _NavBarDesktopState();

  static _NavBarDesktopState of(BuildContext context) {
    // print('_NavBarDesktopState -> ${context}');
    assert(context != null);
    final _NavBarDesktopState result =
        // ignore: deprecated_member_use
        context.ancestorStateOfType(const TypeMatcher<_NavBarDesktopState>());
    // print('_NavBarDesktopState resutl -> ${result}');
    return result;
  }

  @override
  _NavBarDesktopState createState() => new _NavBarDesktopState();
}

class _NavBarDesktopState extends State<NavBarDesktop> {
  String authButtonTitle = "Войти";

  @override
  void initState() {
    print('call init state navbar ${ApiClient.username}');
    if (ApiClient.username != null && ApiClient.username.length > 0)
      authButtonTitle = ApiClient.username;
    super.initState();
  }

  void update() {
    setState(() {
      authButtonTitle = ApiClient.username;
    });
  }

  @override
  Widget build(BuildContext context) {
    return new Container(
      color: primaryColor,
      height: 50,
      padding: EdgeInsets.only(left: 50, right: 50),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: [
          GestureDetector(
              onTap: () {
                LayoutTemplate.of(context).change_page(HomePageDesktop());
              },
              child: Text(
                'UM',
                textAlign: TextAlign.center,
                style: TextStyle(
                    color: textPrimaryColor,
                    fontWeight: FontWeight.w600,
                    fontSize: 40),
              )),
          NavBarItem(
              authButtonTitle,
              () => LayoutTemplate.of(context)
                  .change_page(AuthorizationPageDesktop())),
        ],
      ),
    );
  }

  void auth_page_up(BuildContext context) {
    LayoutTemplate.of(context).change_page(AuthorizationPageDesktop());
  }
}

异常

Error: setState() called in constructor: _NavBarDesktopState#5e1ee(lifecycle state: created, no widget, not mounted)
This happens when you call setState() on a State object for a widget that hasn't been inserted into the widget tree yet. It is not necessary to   
call setState() in the constructor, since the state is already assumed to be dirty when it is initially created.
    at Object.throw_ [as throw] (http://localhost:50572/dart_sdk.js:4334:11)
    at http://localhost:50572/packages/flutter/src/widgets/widget_span.dart.lib.js:13615:23
    at NavBarDesktop._NavBarDesktopState.new.setState (http://localhost:50572/packages/flutter/src/widgets/widget_span.dart.lib.js:13618:26)      
    at NavBarDesktop._NavBarDesktopState.new.update (http://localhost:50572/packages/um/scripts/router.dart.lib.js:1717:12)
    at AuthPageDesktop._AuthorizationPageDesktopState.new.auth (http://localhost:50572/packages/um/scripts/router.dart.lib.js:1932:13)
    at http://localhost:50572/packages/um/scripts/router.dart.lib.js:1926:15
    at _RootZone.runUnary (http://localhost:50572/dart_sdk.js:37457:58)
    at _FutureListener.then.handleValue (http://localhost:50572/dart_sdk.js:32441:29)
    at handleValueCallback (http://localhost:50572/dart_sdk.js:32988:49)
    at Function._propagateToListeners (http://localhost:50572/dart_sdk.js:33026:17)
    at _Future.new.[_completeWithValue] (http://localhost:50572/dart_sdk.js:32869:23)
    at async._AsyncCallbackEntry.new.callback (http://localhost:50572/dart_sdk.js:32891:35)
    at Object._microtaskLoop (http://localhost:50572/dart_sdk.js:37718:13)
    at _startMicrotaskLoop (http://localhost:50572/dart_sdk.js:37724:13)
    at http://localhost:50572/dart_sdk.js:33243:9

您的 _NavBarDesktopState 全局键需要在您的 _NavBarDesktopState class 中初始化,而不是 NavBarDesktop class。它试图在状态创建之前设置全局密钥。

class NavBarDesktop extends StatefulWidget {
  NavBarDesktop({Key key}) : super(key: key);
  _NavBarDesktopState navBarState;

  static _NavBarDesktopState of(BuildContext context) {
    assert(context != null);
    final _NavBarDesktopState result =
        // ignore: deprecated_member_use
        context.ancestorStateOfType(const TypeMatcher<_NavBarDesktopState>());
    return result;
  }

  @override
  _NavBarDesktopState createState() {
    navBar.registerLazySingleton(() => this);
    navBarState = _NavBarDesktopState();
    return navBarState;
  }
}