我所做并导致此错误的场景:1.当我使用热重载按钮时创建登录页面后 2.当我按下登录按钮并且页面状态发生变化时。
最近我决定在我的flutter应用程序中使用riverpod包,所以我使用了hooks_riverpod:^1.0.0-dev.7和flutter_hooks:^0.18.0但是当我在Riverpod和Hooks的帮助下创建我的LoginScreen时,我遇到了一些问题我在下面提供了我的登录信息。
登录屏幕:
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:lambda/configs/sizes/index.dart';
import 'package:lambda/configs/strings.dart';
import 'package:lambda/core/validator/src/mobile_number_validator.dart';
import 'package:lambda/presentation/state_notifiers/auth/index.dart';
import 'package:lambda/presentation/utils/input_formatter/index.dart';
import 'package:lambda/presentation/widgets/alert_message/alert_messge.dart';
import 'package:lambda/presentation/widgets/background/background.dart';
import 'package:lambda/presentation/widgets/progress/progress.dart';
import 'package:lambda/presentation/widgets/spacer/spacer.dart';
import 'package:lambda/routes.dart';
class LoginScreen extends HookConsumerWidget with MobileNumberValidator {
LoginScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context,WidgetRef ref) {
ref.listen<AuthState>(authStateNotifierProvider, (state) {
state.maybeWhen(
orElse: () {},
otpSent: (mobileNumber) {
AppNavigator.replaceWith<String>(
NavigationPaths.verifyLogin, mobileNumber);
},
error: (message) {
AlertMessage(context).warning(message);
});
});
final phoneFieldController = useTextEditingController();
return NormalBackground(
child: Scaffold(
body: Padding(
padding: EdgeInsets.symmetric(
horizontal: LayoutSizes(context).responsive(60)),
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
Strings.pleaseEnterYourMobileNumberForLoginToTheLambda,
style: Theme.of(context).textTheme.caption,
textAlign: TextAlign.center,
),
VSpacer(LayoutSizes(context).marginXXL),
TextFormField(
controller: phoneFieldController,
style: Theme.of(context).textTheme.caption,
textAlign: TextAlign.center,
keyboardType: TextInputType.number,
inputFormatters: [PersianNumberFormatter()],
decoration: const InputDecoration(
hintText: Strings.mobileNumberHint,
),
),
VSpacer(LayoutSizes(context).marginL),
ref.watch(authStateNotifierProvider).maybeMap(
orElse: () {
return ElevatedButton(
onPressed: () {
if (isValidIRMobileNumber(phoneFieldController.text)) {
ref
.read(authStateNotifierProvider.notifier)
.sendOtp(phoneFieldController.text);
} else {
AlertMessage(context).warning(
Strings.isInvalidInput(Strings.mobileNumber));
}
},
style: ButtonStyle(
fixedSize: MaterialStateProperty.all(
Size(double.maxFinite,
LayoutSizes(context).buttonHeightL),
),
),
child: const Text(Strings.next),
);
},
loading: (_) {
return const CircularProgress();
},
),
],
),
),
),
);
}
}
AuthStateProviderNotifier:
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:lambda/configs/strings.dart';
import 'package:lambda/core/extensions/strings.dart';
import 'package:lambda/data/repositories/auth/authentication_repository.dart';
import 'package:lambda/services/http/index.dart';
import 'package:lambda/services/logger/logger.dart';
import 'auth_state.dart';
final authStateNotifierProvider =
StateNotifierProvider<AuthStateNotifier, AuthState>((ref) {
final authRepository = ref.read(authRepositoryProvider);
return AuthStateNotifier(authRepository);
});
class AuthStateNotifier extends StateNotifier<AuthState> {
final AuthenticationRepository _repository;
AuthStateNotifier(this._repository) : super(const AuthState.initial());
Future<void> sendOtp(String mobileNumber) async {
try {
state = const AuthState.loading();
await _repository.sendValidationCode(
mobileNumber: mobileNumber.convertToEnNum());
state = AuthState.otpSent(mobileNumber: mobileNumber);
} catch (e, s) {
_handleError(e, s);
}
}
Future<void> verifyOtp(String mobileNumber, String code) async {
try {
state = const AuthState.loading();
await _repository.login(
mobileNumber: mobileNumber.convertToEnNum(),
verificationCode: code.convertToEnNum());
state = const AuthState.authenticated();
} catch (e, s) {
_handleError(e, s);
}
}
void _handleError(Object e, StackTrace s) {
Logger().info('error : $e stack: $s');
if (e is NetworkExceptionX) {
state = AuthState.error(
errorMessage: e.messageForUser ?? Strings.someErrorHappened);
} else {
state = const AuthState.error(errorMessage: Strings.someErrorHappened);
}
}
}
跑:
======== Exception caught by widgets library =======================================================
The following assertion was thrown building LoginScreen(dirty, dependencies: [_LocalizationsScope-[GlobalKey#aacaf], UncontrolledProviderScope, _InheritedTheme], state: _ConsumerState#cf20e, useTextEditingController: TextEditingController#f5c6d(TextEditingValue(text: ┤├, selection: TextSelection(baseOffset: -1, extentOffset: -1, affinity: TextAffinity.downstream, isDirectional: false), composing: TextRange(start: -1, end: -1)))):
Looking up a deactivated widget's ancestor is unsafe.
At this point the state of the widget's element tree is no longer stable.
To safely refer to a widget's ancestor in its dispose() method, save a reference to the ancestor by calling dependOnInheritedWidgetOfExactType() in the widget's didChangeDependencies() method.
The relevant error-causing widget was:
LoginScreen file:///Users/taleb/FlutterProjects/lambda/lib/routes.dart:40:36
When the exception was thrown, this was the stack:
#0 Element._debugCheckStateIsActiveForAncestorLookup.<anonymous closure> (package:flutter/src/widgets/framework.dart:3944:9)
#1 Element._debugCheckStateIsActiveForAncestorLookup (package:flutter/src/widgets/framework.dart:3958:6)
#2 Element.findAncestorWidgetOfExactType (package:flutter/src/widgets/framework.dart:3996:12)
#3 debugCheckHasMediaQuery.<anonymous closure> (package:flutter/src/widgets/debug.dart:218:50)
#4 debugCheckHasMediaQuery (package:flutter/src/widgets/debug.dart:234:4)
...
====================================================================================================
======== Exception caught by widgets library =======================================================
The following assertion was thrown building LoginScreen(dirty, dependencies: [_LocalizationsScope-[GlobalKey#aacaf], UncontrolledProviderScope, _InheritedTheme], state: _ConsumerState#cf20e, useTextEditingController: TextEditingController#f5c6d(TextEditingValue(text: ┤├, selection: TextSelection(baseOffset: -1, extentOffset: -1, affinity: TextAffinity.downstream, isDirectional: false), composing: TextRange(start: -1, end: -1)))):
Looking up a deactivated widget's ancestor is unsafe.
At this point the state of the widget's element tree is no longer stable.
To safely refer to a widget's ancestor in its dispose() method, save a reference to the ancestor by calling dependOnInheritedWidgetOfExactType() in the widget's didChangeDependencies() method.
The relevant error-causing widget was:
LoginScreen file:///Users/taleb/FlutterProjects/lambda/lib/routes.dart:40:36
When the exception was thrown, this was the stack:
#0 Element._debugCheckStateIsActiveForAncestorLookup.<anonymous closure> (package:flutter/src/widgets/framework.dart:3944:9)
#1 Element._debugCheckStateIsActiveForAncestorLookup (package:flutter/src/widgets/framework.dart:3958:6)
#2 Element.findAncestorWidgetOfExactType (package:flutter/src/widgets/framework.dart:3996:12)
#3 debugCheckHasMediaQuery.<anonymous closure> (package:flutter/src/widgets/debug.dart:218:50)
#4 debugCheckHasMediaQuery (package:flutter/src/widgets/debug.dart:234:4)
...
====================================================================================================
这些错误发生在我在 HookConsumerWidget 类中使用 TextField 时。我正在使用 HookConsumerWidget 而不是 StatefullWidget。我也尝试使用 StatefullConsumerWidget,但问题没有解决。(ConsumerStatefulWidget+riverPod)。我的问题是我们如何在 HookConsumerWidget + Riverpod 中使用 Textfield ????
如果你想自己运行它,我在我的 Github 上提供了这个错误的示例代码: smaple_hook_riverpod