У меня есть ConsumerWidget, который я использую, чтобы следить за состоянием провайдера. В любом случае все работает, кроме моего TextEditingControllers. Всякий раз, когда я вводю что-то в текстовое поле и нажимаю кнопку «Готово» на клавиатуре телефона, текстовые поля снова становятся пустыми. Я думаю, это связано с состоянием этого виджета. Итак, мой вопрос: как мне использовать TextEditingController внутри ConsumerWidget, у которого нет createState метода?
Вот мой код. Заранее спасибо:
class MainPage extends ConsumerWidget {
const MainPage({super.key});
@override
Widget build(BuildContext context, ref) {
// provider
final roomListData = ref.watch(roomDataProvider);
final roomService = RoomService();
final roomIDController = TextEditingController();
final roomPasswordController = TextEditingController();
// UI screen size
final size = MediaQuery.of(context).size;
double deviceWidth = size.width;
double deviceHeight = size.height;
return Scaffold(
backgroundColor: bluePrimary,
body: SingleChildScrollView(
child: roomListData.when(
data: (data) {
List<RoomModelResponse> roomList =
data.map((room) => room).toList();
return SafeArea(
child: Container(
padding:
const EdgeInsets.symmetric(horizontal: 36, vertical: 16),
child: Column(
//crossAxisAlignment: CrossAxisAlignment.center,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
IconButton(
iconSize: deviceWidth * 0.09,
icon: const Icon(Icons.person_outline,
color: orangePrimary),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
const DetailedProfilePage()));
},
),
IconButton(
icon: const Icon(
Icons.add,
color: orangePrimary,
),
iconSize: deviceWidth * 0.09,
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
const CreateRoomScreen()),
);
},
)
],
),
SizedBox(height: deviceHeight * 0.04),
Align(
alignment: Alignment.centerLeft,
child: Text("Join room",
style: TextStyle(
fontFamily: 'Chalet',
fontSize: deviceWidth * 0.05,
color: whitePrimary,
fontWeight: FontWeight.w100,
)),
),
SizedBox(height: deviceHeight * 0.008),
// room ID textField
SizedBox(
width: MediaQuery.of(context).size.width * 0.85,
child: TextField(
controller: roomIDController,
decoration: InputDecoration(
filled: true,
fillColor: whitePrimary,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide.none),
hintText: 'Enter room ID to join it',
hintStyle: const TextStyle(
color: Color.fromARGB(255, 174, 173, 173))),
),
),
SizedBox(height: deviceHeight * 0.01),
// room password textField
SizedBox(
width: MediaQuery.of(context).size.width * 0.85,
child: TextField(
obscureText: true,
controller: roomPasswordController,
decoration: InputDecoration(
filled: true,
fillColor: whitePrimary,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide.none),
hintText:
'Leave blank if the room has no password',
hintStyle: const TextStyle(
color: Color.fromARGB(255, 174, 173, 173))),
),
),
...





При работе с TextEditingController вам необходимо иметь StatefulWidget, поскольку каждый раз, когда изменяются параметры вашего виджета, он запускает метод build(), который воссоздает ваши контроллеры, делая их пустыми. Обратитесь к этой части руководства по флаттеру.
При работе с последними версиями Riverpod вам необходимо использовать ConsumerStatefulWidget, что синтаксически точно так же, как StatefulWidget, но с добавлением «Consumer» перед каждым именем класса.
Полученный виджет должен создать
// probably some other vars too
final roomIDController = TextEditingController();
final roomPasswordController = TextEditingController();
вне метода build(), внутри класса _State
Вы также можете использовать хуки (пакет flutter_hooks) и использовать HookConsumerWidget. Тогда ваш код будет еще короче. Вам также понадобится пакет hooks_riverpod:
class MainPage extends HookConsumerWidget {
const MainPage({super.key});
@override
Widget build(BuildContext context, ref) {
final roomListData = ref.watch(roomDataProvider);
final roomIDController = useTextEditingController();
final roomPasswordController = useTextEditingController();
return Scaffold(...);
}
}
Хуки сами заботятся о жизненном цикле объектов, поэтому вам не придется вручную удалять их с помощью метода dispose.
Ссылки:
Riverpod не рекомендует использовать поставщиков для хранения TextControllers. Вы можете использовать ConsumerStatefulWidget для локального состояния.
Также не забудьте избавиться от этих контроллеров в своем методе
dispose.