簡體   English   中英

Flutter bloc/錯誤/查找已停用小部件的祖先是不安全的。 / Firebase 注冊

[英]Flutter bloc/ Error / Looking up a deactivated widget's ancestor is unsafe. / Firebase SignUp

描述

我嘗試使用 bloc/cubit 為我的應用程序設置 Firebase 注冊功能,但遇到以下錯誤。

查找已停用小部件的祖先是不安全的。 此時小部件的元素樹的 state 不再穩定。 要在其 dispose() 方法中安全地引用小部件的祖先,請通過在小部件的 didChangeDependencies() 方法中調用dependOnInheritedWidgetOfExactType() 來保存對祖先的引用。

這個錯誤信息似乎是說CustomButton package中的以下代碼不穩定。

 context.read<SignupCubit>().signupWithCredentials().whenComplete(() {
              User user = User(
                id: context.read<SignupCubit>().state.user!.uid,
                name: '',
                age: 0,
              );

在調試模式下不會發生此錯誤。 當我逐行運行代碼時,該過程繼續進行而沒有問題。 我不知道原因。

我已嘗試解決此錯誤,但絕不是不工作。

CustomButton顯示在注冊頁面上的按鈕小部件。 當用戶在輸入 email 和密碼后按下按鈕時,將創建用戶帳戶。 然后將在 Firebase 數據庫上創建用戶的 userid、name 和 age 文檔字段。

class CustomButton extends StatelessWidget {
  final TabController? tabController;
  final String text;
  CustomButton({
    Key? key,
    this.tabController,
    this.text = 'START',
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
          return DecoratedBox(
          decoration: BoxDecoration(
            borderRadius: BorderRadius.circular(10),
            gradient: LinearGradient(
              colors: [
                Theme.of(context).primaryColor,
                Theme.of(context).primaryColorLight
              ],
            ),
          ),
          child: ElevatedButton(
            style: ElevatedButton.styleFrom(
                elevation: 0, backgroundColor: Colors.transparent),
            onPressed: () {
              if (tabController!.index <= 4) {
                tabController!.animateTo(tabController!.index + 1);
              } else {
                Navigator.pushNamed(context, '/');
              }
              if (tabController!.index == 2) {
                context
                    .read<SignupCubit>()
                    .signupWithCredentials()
                    .whenComplete(() {
                  User user = User(
                    id: context.read<SignupCubit>().state.user!.uid,
                    name: '',
                    age: 0,
                  );
                  context
                      .read<OnboardingBloc>()
                      .add(StartOnboarding(user: user));
                });
              }
            },
            child: SizedBox(
              child: Center(
                child: Text(
                  text,
                  style: Theme.of(context)
                      .textTheme
                      .headline4!
                      .copyWith(color: Colors.white),
                ),
              ),
              width: double.infinity,
            ),
          ));
    }
  }

注冊Cubit

class SignupCubit extends Cubit<SignupState> {
  final AuthRepository? _authRepository;
  SignupCubit({ AuthRepository? authRepository})
      : _authRepository = authRepository,
        super(SignupState.initial());

  void emailChanged(String value) {
    emit(state.copywith(email: value, status: SignupStatus.initial));
  }

  void passwordChanged(String value) {
    emit(state.copywith(password: value, status: SignupStatus.initial));
  }

  Future<void> signupWithCredentials() async {
    if (!state.isValid || state.status == SignupStatus.submitting) return;
    emit(state.copywith(status: SignupStatus.submitting));
    try {
      var user = await _authRepository!.signUp(
        email: state.email,
        password: state.password,
      );
      emit(state.copywith(
        status: SignupStatus.success,
        user: user,
      ));
    } catch (e) {
      debugPrint('$e');
    }
  }
}

注冊狀態

enum SignupStatus { initial, submitting, success, error }

class SignupState extends Equatable {
  final String email;
  final String password;
  final SignupStatus status;
  final auth.User? user;

  const SignupState(
      {required this.email,
      required this.password,
      required this.status,
      this.user,
      });

  factory SignupState.initial() {
    return const SignupState(
        email: '', password: '', status: SignupStatus.initial, user: null,);
  }

  SignupState copywith({
    String? email,
    String? password,
    SignupStatus? status,
    auth.User? user,
    String? uid,
  }) {
    return SignupState(
        email: email ?? this.email,
        password: password ?? this.password,
        status: status ?? this.status,
        user: user ?? this.user,
        );
  }

  bool get isValid => email.isNotEmpty && password.isNotEmpty;

  @override
  bool get stringify => true;

  @override
  List<Object?> get props => [email, password, status, user];
}

授權庫

class AuthRepository extends BaseAuthRepository {
  final auth.FirebaseAuth _firebaseAuth;
  AuthRepository({auth.FirebaseAuth? firebaseAuth})
      : _firebaseAuth = firebaseAuth ?? auth.FirebaseAuth.instance;

  @override
  Future<auth.User?> signUp(
      {required String email, required String password}) async {
    final credential = await _firebaseAuth.createUserWithEmailAndPassword(
        email: email, password: password);
    final user = credential.user;
    return user;
  }
}

我放棄了使用context.read<SignupCubit>().state.user.,uid,但想出了使用 BlocConsumer 的想法!

這真的解決了堆棧。 我希望這可以幫助遇到同樣問題的人......

class EmailScreen extends StatelessWidget {
  final TabController tabController;
  const EmailScreen({Key? key, required this.tabController}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return BlocConsumer<SignupCubit, SignupState>(
      listenWhen: (previous, current) => current.status == SignupStatus.success,
      listener: (context, state) {
        User user = User(
          id: state.user!.uid,
          name: '',
          age: 0,
        );
        context.read<OnboardingBloc>().add(StartOnboarding(user: user));
      },
      builder: (context, state) {
        return Padding(
          padding: const EdgeInsets.symmetric(horizontal: 30.0, vertical: 50),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: [
              Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  const CustomTextHeader(text: 'What\'s Your Email Address?'),
                  CustomTextfield(
                    text: 'ENTER YOUR EMAIL',
                    onChanged: (value) {
                      context.read<SignupCubit>().emailChanged(value);
                    },
                  ),
                  const SizedBox(height: 100),
                  const CustomTextHeader(text: 'Choose a Password'),
                  CustomTextfield(
                    text: 'ENTER YOUR PASSWORD',
                    onChanged: (value) {
                      context.read<SignupCubit>().passwordChanged(value);
                    },
                  ),
                ],
              ),
              Column(
                children: [
                  const StepProgressIndicator(
                    totalSteps: 5,
                    currentStep: 1,
                    selectedColor: Colors.grey,
                    unselectedColor: Colors.purpleAccent,
                  ),
                  const SizedBox(
                    height: 10,
                  ),
                  CustomButton(
                    tabController: tabController,
                    text: 'NEXT STEP',
                    isCompleted: (state.email.isEmpty || state.password.isEmpty)
                        ? false
                        : true,
                  )
                ],
              ),
            ],
          ),
        );
      },
    );
  }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM