You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中setState刷新后TextEditingController数据丢失的解决方法

解决TextField在setState后丢失输入内容的问题

你的问题根源是在build方法中直接给TextEditingController的text属性赋值,每次调用setState触发Widget重建时,都会用userData的原始值覆盖用户输入的内容,导致输入丢失。

解决步骤:

  1. 将控制器的初始值设置逻辑移到initState方法中,只在Widget初始化时执行一次
  2. 如果需要响应userData的外部更新,可以通过didChangeDependencies方法处理,避免每次build都重置输入内容

修改后的完整代码:

import 'package:attend/constants.dart/enums.dart';
import 'package:attend/providers/user_data_provider.dart';
import 'package:attend/screens/faculty_screens/faculty_home_screen.dart';
import 'package:attend/screens/student_screens/screens/student_screen.dart';
import 'package:attend/widgets.dart/profile_image.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:flutter/cupertino.dart';

class ProfileDetailScreen extends StatefulWidget {
  static const routeName = '/profile-detail-screen';
  const ProfileDetailScreen({super.key});

  @override
  State<ProfileDetailScreen> createState() => _ProfileDetailScreenState();
}

class _ProfileDetailScreenState extends State<ProfileDetailScreen> {
  final _formKey = GlobalKey<FormState>();

  var selectedGender = 'Male';
  final _nameCon = TextEditingController();
  final _surnameCon = TextEditingController();
  final _enrollmentCon = TextEditingController();
  var isValid = false;

  @override
  void initState() {
    super.initState();
    // 在初始化时设置控制器初始值,只执行一次
    WidgetsBinding.instance.addPostFrameCallback((_) {
      final userData = Provider.of<UserDataProvider>(context, listen: false);
      _nameCon.text = userData.name ?? '';
      _surnameCon.text = userData.surname ?? '';
      if (userData.role == Roles.student) {
        _enrollmentCon.text = userData.enrollmentNo ?? ''; // 若有学号字段可补充此逻辑
      }
    });
  }

  @override
  void dispose() {
    _nameCon.dispose();
    _surnameCon.dispose();
    _enrollmentCon.dispose();
    super.dispose();
  }

  void saveData() async {
    isValid = _formKey.currentState!.validate();

    if (!isValid) {
      return;
    }

    var gender = Genders.Other;
    if (selectedGender == Genders.Male.name) {
      gender = Genders.Male;
    } else if (selectedGender == Genders.Female.name) {
      gender = Genders.Female;
    }
    // 此处可添加保存数据到userData的逻辑
  }

  @override
  Widget build(BuildContext context) {
    final userData = Provider.of<UserDataProvider>(context, listen: false);

    return Scaffold(
      appBar: AppBar(
        title: const Text('Profile details'),
        actions: [
          IconButton(
              onPressed: saveData,
              icon: const Icon(Icons.save))
        ],
      ),
      body: Padding(
        padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
        child: Form(
          key: _formKey,
          child: Column(
            children: [
              ProfileImage(selectedGender: selectedGender),
              const SizedBox(height: 20),

              //! name textfield
              TextFormField(
                textCapitalization: TextCapitalization.sentences,
                decoration: InputDecoration(
                  contentPadding:
                      const EdgeInsets.symmetric(horizontal: 15, vertical: 10),
                  focusedBorder: OutlineInputBorder(
                    borderSide: const BorderSide(color: Colors.grey),
                    borderRadius: BorderRadius.circular(15),
                  ),
                  errorBorder: OutlineInputBorder(
                    borderRadius: BorderRadius.circular(15),
                    borderSide: const BorderSide(color: Colors.red),
                  ),
                  enabledBorder: OutlineInputBorder(
                    borderRadius: BorderRadius.circular(15),
                    borderSide: const BorderSide(color: Colors.grey),
                  ),
                  filled: true,
                  fillColor: Colors.grey.shade100,
                  labelText: 'Enter your name',
                  labelStyle: const TextStyle(color: Colors.black, fontSize: 15),
                ),
                validator: (value) {
                  if (value!.isEmpty) {
                    return 'Please enter name!';
                  } else if (value.length <= 2) {
                    return 'Name at least 3 character long!';
                  }
                  return null;
                },
                controller: _nameCon,
                textInputAction: TextInputAction.next,
              ),
              const SizedBox(height: 20),

              //! surname textfield
              TextFormField(
                textCapitalization: TextCapitalization.sentences,
                decoration: InputDecoration(
                  contentPadding:
                      const EdgeInsets.symmetric(horizontal: 15, vertical: 10),
                  focusedBorder: OutlineInputBorder(
                    borderSide: const BorderSide(color: Colors.grey),
                    borderRadius: BorderRadius.circular(15),
                  ),
                  errorBorder: OutlineInputBorder(
                    borderRadius: BorderRadius.circular(15),
                    borderSide: const BorderSide(color: Colors.red),
                  ),
                  enabledBorder: OutlineInputBorder(
                    borderRadius: BorderRadius.circular(15),
                    borderSide: const BorderSide(color: Colors.grey),
                  ),
                  filled: true,
                  fillColor: Colors.grey.shade100,
                  labelText: 'Enter your surname',
                  labelStyle: const TextStyle(color: Colors.black, fontSize: 15),
                ),
                validator: (value) {
                  if (value!.isEmpty) {
                    return 'Please enter surname!';
                  } else if (value.length <= 2) {
                    return 'Surname at least 3 character long!';
                  }
                  return null;
                },
                controller: _surnameCon,
                textInputAction: userData.role == Roles.student
                    ? TextInputAction.next
                    : TextInputAction.done,
              ),
              const SizedBox(height: 20),

              //! if student then he has to add enrollment no
              if (userData.role == Roles.student)
                TextFormField(
                  textCapitalization: TextCapitalization.sentences,
                  decoration: InputDecoration(
                    contentPadding:
                        const EdgeInsets.symmetric(horizontal: 15, vertical: 10),
                    focusedBorder: OutlineInputBorder(
                      borderSide: const BorderSide(color: Colors.grey),
                      borderRadius: BorderRadius.circular(15),
                    ),
                    errorBorder: OutlineInputBorder(
                      borderRadius: BorderRadius.circular(15),
                      borderSide: const BorderSide(color: Colors.red),
                    ),
                    enabledBorder: OutlineInputBorder(
                      borderRadius: BorderRadius.circular(15),
                      borderSide: const BorderSide(color: Colors.grey),
                    ),
                    filled: true,
                    fillColor: Colors.grey.shade100,
                    labelText: 'Enter your enrollment no',
                    labelStyle: const TextStyle(color: Colors.black, fontSize: 15),
                  ),
                  validator: (value) {
                    if (value!.isEmpty) {
                      return 'Please enter enrollment no!';
                    } else if (value.length <= 2) {
                      return 'Please enter valid enrollment no!';
                    }
                    return null;
                  },
                  controller: _enrollmentCon,
                  textInputAction: TextInputAction.done,
                ),
              const SizedBox(height: 20),

              //! selected gender
              Row(
                children: [
                  const Text(
                    'Gender ',
                    style: TextStyle(fontSize: 17),
                  ),
                  const SizedBox(width: 40),
                  DropdownButton<String>(
                    dropdownColor: Colors.purple.shade50,
                    value: selectedGender,
                    onChanged: (newValue) {
                      setState(() {
                        selectedGender = newValue!;
                      });
                    },
                    items: <String>['Male', 'Female', 'Others']
                        .map<DropdownMenuItem<String>>((String value) {
                      return DropdownMenuItem<String>(
                        value: value,
                        child: Text(
                          value,
                          style: const TextStyle(
                              fontWeight: FontWeight.normal, fontSize: 15),
                        ),
                      );
                    }).toList(),
                  ),
                ],
              ),
            ],
          ),
        ),
      ),
    );
  }
}

额外说明:

  • 使用WidgetsBinding.instance.addPostFrameCallback是因为initState阶段无法直接获取Provider数据,需等待Widget挂载完成后再执行
  • 若后续userData有外部更新需要同步到输入框,可重写didChangeDependencies方法,添加判断逻辑避免重复覆盖用户输入

内容的提问来源于stack exchange,提问作者Smit Prajapati

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 03:04:57