![](/img/trans.png)
[英]Unhandled Exception: Looking up a deactivated widget's ancestor is unsafe. At this point the state of the widget's element tree is no longer stable
[英]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.