I have a ConsumerWidget
, which I’m using to watch the state of a provider. Anyways everything is working, besides my TextEditingControllers
. Whenever I type something into the text field and click the done button on the phone keyboard, the textfields goes empty again. I think this is due to the state of that widget. So my question is how do I use the TextEditingController
inside the ConsumerWidget
, which has no createState
method?
Here is my code. Thanks in advance:
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))),
),
),
...
2
Answers
You need to have StatefulWidget when working with
TextEditingController
since every time parameters of your widget change, it triggersbuild()
method, which recreates your controllers, making them empty. Refer to this part of flutter guide.When working with recent versions of riverpod you need to use
ConsumerStatefulWidget
which is exactly likeStatefulWidget
syntactically, but with "Consumer" before every class name.Your resulting widget should create
outside of the
build()
method, inside of _State classYou can also use hooks (
flutter_hooks
package) and useHookConsumerWidget
. Then your code will be even shorter. You will also need a packagehooks_riverpod
:Hooks take care of the lifecycle of objects themselves, so you don’t have to manually dispose of them via the
dispose
method.Links: