简体   繁体   English

当 state 更改时,有状态小部件不重建子小部件(颤振)

[英]Stateful widget not rebuilding child widget when state changes (Flutter)

I'm building a form that signs up the user on Firebase, and where the ElevatedButton either displays "CREATE YOUR ACCOUNT" or a CircularProgressIndicator, based on the state of isLoading.我正在构建一个表单,用于在 Firebase 上注册用户,其中 ElevatedButton 显示“创建您的帐户”或 CircularProgressIndicator,基于 isLoading 的 state。 Yet, the button's child doesn't change based on isLoading.然而,按钮的子元素不会根据 isLoading 改变。

The states does change -- I'm printing out isLoading in the middle of my onPressed methode, and I do see it as true .状态确实发生了变化——我在我的 onPressed 方法中间打印出 isLoading ,我确实认为它是true

Why isn't the button changing its child?为什么按钮不改变它的孩子?

import 'package:flutter/material.dart';
import 'package:tedy/components/custom_text_form_field.dart';
import 'package:tedy/components/custom_wrapper.dart';

class EmployerOnboardingOneView extends StatefulWidget {
  const EmployerOnboardingOneView({Key? key}) : super(key: key);

  @override
  State<EmployerOnboardingOneView> createState() =>
      _EmployerOnboardingOneViewState();
}

class _EmployerOnboardingOneViewState extends State<EmployerOnboardingOneView> {
  var firstNameController = TextEditingController();
  var lastNameController = TextEditingController();
  var emailController = TextEditingController();
  var passwordController = TextEditingController();
  var passwordConfirmController = TextEditingController();

  bool isLoading = false;

  @override
  Widget build(BuildContext context) {
    var screenWidth = MediaQuery.of(context).size.width;

    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.white,
        centerTitle: true,
        title: SizedBox(
          height: 50,
          child: Image.asset(
            'assets/images/tedy_logo_color.png',
            filterQuality: FilterQuality.high,
          ),
        ),
      ),
      body: CustomWrapper(
        maxWidth: 400,
        children: [
          Text(
            'Create a Tedy account for your company',
            style: Theme.of(context).textTheme.headline3,
            textAlign: TextAlign.center,
          ),
          const SizedBox(
            height: 20,
          ),
          CustomTextFormField(
              controller: firstNameController, label: 'First Name'),
          const SizedBox(
            height: 20,
          ),
          CustomTextFormField(
              controller: lastNameController, label: 'Last Name'),
          const SizedBox(
            height: 20,
          ),
          CustomTextFormField(controller: emailController, label: 'Email'),
          const SizedBox(
            height: 20,
          ),
          CustomTextFormField(
              controller: passwordController,
              isPassword: true,
              label: 'Password'),
          const SizedBox(
            height: 20,
          ),
          CustomTextFormField(
              controller: passwordConfirmController,
              isPassword: true,
              label: 'Confirm your password'),
          const SizedBox(
            height: 20,
          ),
          SizedBox(
            width: double.infinity,
            height: 50,
            child: ElevatedButton(
              style: ElevatedButton.styleFrom(
                  primary: Theme.of(context).primaryColor),
              onPressed: () async {
                setState(() {
                  isLoading = true;
                });
                if (passwordController.text != passwordConfirmController.text) {
                  ScaffoldMessenger.of(context).showSnackBar(
                    const SnackBar(
                      content: Text('Passwords must match'),
                      backgroundColor: Colors.red,
                    ),
                  );
                } else {
                  try {
                    FirebaseAuth.instance
                        .createUserWithEmailAndPassword(
                            email: emailController.text,
                            password: passwordController.text)
                        .then((value) {
                      Navigator.pushNamedAndRemoveUntil(
                          context, '/', (route) => false);
                    });
                    print(isLoading);
                  } on FirebaseAuthException catch (e) {
                    ScaffoldMessenger.of(context).showSnackBar(
                      SnackBar(
                        content: Text(e.message != null
                            ? e.message as String
                            : 'There was an error.'),
                        backgroundColor: Colors.red,
                      ),
                    );
                  }
                }
                setState(() {
                  isLoading = false;
                });
              },
              child: isLoading
                  ? const SizedBox(
                      width: 30,
                      height: 30,
                      child: CircularProgressIndicator(
                        color: Colors.white,
                      ),
                    )
                  : const Text('CREATE YOUR ACCOUNT'),
            ),
          )
        ],
      ),
    );
  }
}

createUserWithEmailAndPassword is async, so you have to await it createUserWithEmailAndPassword 是异步的,所以你必须等待它

await FirebaseAuth.instance
                        .createUserWithEmailAndPassword(
                            email: emailController.text,
                            password: passwordController.text);
Navigator.pushNamedAndRemoveUntil(
                          context, '/', (route) => false);

Your code set isLoading to true, does the password logic and calls this method.您的代码集 isLoading 为 true,执行密码逻辑并调用此方法。 But since you don't await it here it just skips it and calls the setState with isLoading = false.但是由于您不在这里等待它,它只是跳过它并使用 isLoading = false 调用 setState。

You are using then for the future.您将then用于未来。 so the last isLoading = false;所以最后一个isLoading = false; executed when you pressed the button.按下按钮时执行。 You can change state inside.then instead of end.您可以更改 state inside.then 而不是 end。 Also you can add inside FirebaseAuthException .您也可以在FirebaseAuthException中添加。 make sure to remove last isLoading = false;确保删除最后一个isLoading = false;

FirebaseAuth.instance
    .createUserWithEmailAndPassword(
        email: emailController.text,
        password: passwordController.text)
    .then((value) {
  setState(() {
    isLoading = false;
  });
  Navigator.pushNamedAndRemoveUntil(
      context, '/', (route) => false);
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在没有Stateless/Stateful Widget的情况下获取Flutter中Future Function的返回值 - getting the return value of Future Function in Flutter without Stateless/Stateful Widget 如何为有状态小部件编写测试? - How to write a test for a stateful widget? Flutter:当小部件没有父/子关系时,如何从小部件 B 调用小部件 A 中的 function? - Flutter: How do I call a function in widget A from widget B when the widgets do not have a parent/child relationship? 如何在 Firebase 存储(颤振)中的文件更改时重建个人资料图片小部件 - How to rebuild profile picture widget on changes to file in Firebase Storage (Flutter) Flutter - function 中的变量在构建小部件时可用 - Flutter - Variable in function available when building Widget Flutter - 小部件变量始终为 null - Flutter - widget variables are always null 无法在 flutter 中构建自定义小部件 - Not able to build custom widget in flutter Flutter:使用来自 firebase firestore 的 Boolean 值的表达式隐藏或显示子窗口小部件 - Flutter: Hide or Display Child Widget using an Expression from Boolean values from firebase firestore 如何将从 Home 小部件获取的数据传递给 flutter 中的子小部件? - How to pass the data get from Home widget to it's child widgets in flutter? Flutter JIT编译和动态widget树 - Flutter JIT compilation and dynamic widget tree
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM