Flutter中TextField的onChanged赋值变量无效,回调更新变量后打印仍为null的问题排查
Hey there! Let's break down why your newTaskTitle variable is showing up as null when you print it, and how to fix this issue.
The Root Cause
You’ve defined String? newTaskTitle; directly inside the widget’s body (which lives within the build method). Here’s the problem: Flutter rebuilds the widget tree frequently—like when the keyboard pops up, or any state changes in your app. Every time this happens, the build method runs again, and your newTaskTitle variable gets reinitialized to null—even if you’d set it via onChanged earlier. That’s why tapping the "Add" button prints null instead of your input text.
Solution 1: Use a StatefulWidget's Member Variable
Move your newTaskTitle variable into the state class of a StatefulWidget (not inside the build method). This way, the variable’s value persists across widget rebuilds.
Here’s the corrected code:
class TaskAddScreen extends StatefulWidget { const TaskAddScreen({super.key}); @override State<TaskAddScreen> createState() => _TaskAddScreenState(); } class _TaskAddScreenState extends State<TaskAddScreen> { // Store the variable here, not inside build() String? newTaskTitle; @override Widget build(BuildContext context) { return Scaffold( body: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ TextField( cursorColor: Colors.white38, decoration: const InputDecoration( enabledBorder: UnderlineInputBorder( borderSide: BorderSide(color: Colors.white38), ), focusedBorder: UnderlineInputBorder( borderSide: BorderSide(color: Colors.white38), ), ), textAlign: TextAlign.center, autofocus: true, onChanged: (newText) { // Update the state variable directly newTaskTitle = newText; }, ), const SizedBox(height: 20), FlatButton( color: Colors.white, onPressed: () { print(newTaskTitle); // Now this will print your input text! }, child: const Text( 'Add', style: TextStyle( fontSize: 15, fontWeight: FontWeight.bold, color: Colors.black, ), ), ), ], ), ); } }
Solution 2: Use TextEditingController (Recommended)
For managing TextField input, Flutter’s TextEditingController is the more robust approach. It handles text state internally, so you don’t need to manually update a variable via onChanged.
Here’s how to implement it:
class TaskAddScreen extends StatefulWidget { const TaskAddScreen({super.key}); @override State<TaskAddScreen> createState() => _TaskAddScreenState(); } class _TaskAddScreenState extends State<TaskAddScreen> { // Initialize the controller final TextEditingController _taskController = TextEditingController(); @override void dispose() { // Always dispose the controller to avoid memory leaks _taskController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( body: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ TextField( cursorColor: Colors.white38, decoration: const InputDecoration( enabledBorder: UnderlineInputBorder( borderSide: BorderSide(color: Colors.white38), ), focusedBorder: UnderlineInputBorder( borderSide: BorderSide(color: Colors.white38), ), ), textAlign: TextAlign.center, autofocus: true, controller: _taskController, // Bind the controller to the TextField ), const SizedBox(height: 20), FlatButton( color: Colors.white, onPressed: () { // Get the text directly from the controller print(_taskController.text); }, child: const Text( 'Add', style: TextStyle( fontSize: 15, fontWeight: FontWeight.bold, color: Colors.black, ), ), ), ], ), ); } }
This approach is better because it gives you extra control—like setting initial text, clearing the input, or listening to text changes with addListener—and it avoids manual state management errors.
内容的提问来源于stack exchange,提问作者Bryar Laiq

