Flutter中如何用Cloud Firestore预填编辑账户表单?
问题描述
在Cloud Firestore中存储了一组账户数据,编辑账户时希望表单预填已有信息。已成功获取到正确的账户信息并能在控制台打印,但表单字段无法加载这些预填数据。尝试修改异步方法、调整获取数据的位置,仍未解决。相关代码如下:
import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:flutter/material.dart'; import './nav_bar.dart'; class EditSettings extends StatefulWidget { const EditSettings({ super.key, }); static const routeName = '/edit-settings'; @override State<EditSettings> createState() => _EditSettingsState(); } class _EditSettingsState extends State<EditSettings> { final _form = GlobalKey<FormState>(); void homeRoute(BuildContext ctx) { Navigator.of(ctx).pushReplacementNamed(NavBar.routeName); } final _urlFocusNode = FocusNode(); final _usernameFocusNode = FocusNode(); final _passwordFocusNode = FocusNode(); //final _confirmPassFocusNode = FocusNode(); var _initValues = { 'siteName': '', 'siteUrl': '', 'userName': '', 'password': '', }; @override void dispose() { _urlFocusNode.dispose(); _usernameFocusNode.dispose(); _passwordFocusNode.dispose(); //_confirmPassFocusNode.dispose(); super.dispose(); } var _isInit = true; bool _passwordVisible = false; @override void initState() { _passwordVisible = false; super.initState(); } @override void didChangeDependencies() async { if (_isInit) { if (ModalRoute.of(context)!.settings.arguments != null) { final accountId = ModalRoute.of(context)!.settings.arguments as String; if (accountId.isNotEmpty) { final _editedAccount = await FirebaseFirestore.instance.collection('accounts').doc(accountId).get(); print(Text(_editedAccount.data().toString())); _initValues = { 'siteName': _editedAccount['siteName'], 'siteUrl': _editedAccount['url'], 'userName': _editedAccount['username'], 'password': _editedAccount['password'], }; } } _isInit = false; } super.didChangeDependencies(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Edit Settings')), body: Padding( padding: const EdgeInsets.only( top: 40, left: 10, right: 10, ), child: Form( key: _form, child: ListView( children: <Widget>[ TextFormField( initialValue: _initValues['siteName'], // 此处无法加载数据 decoration: const InputDecoration( border: OutlineInputBorder(), labelText: 'Name of Site', hintText: 'Site Name', ), // 省略其他字段和代码 ), ], ), ), ), ); } }
解决方案
导致表单无法预填数据的核心问题有两个:
- 异步更新数据后未触发UI重建:异步获取Firestore数据后,虽然修改了
_initValues,但没有调用setState()通知框架更新UI,表单字段依然使用初始的空值。 didChangeDependencies方法不应标记为async:这个方法的返回类型是void,标记为async会让它返回Future,可能导致Flutter框架的生命周期逻辑异常。
修改后的代码如下,重点调整didChangeDependencies部分:
@override void didChangeDependencies() { if (_isInit) { // 将异步逻辑封装在内部async函数中 Future.microtask(() async { if (ModalRoute.of(context)!.settings.arguments != null) { final accountId = ModalRoute.of(context)!.settings.arguments as String; if (accountId.isNotEmpty) { final _editedAccount = await FirebaseFirestore.instance.collection('accounts').doc(accountId).get(); print(_editedAccount.data().toString()); // 简化打印,不需要Text组件 setState(() { _initValues = { 'siteName': _editedAccount['siteName'] ?? '', // 添加空值判断,避免null异常 'siteUrl': _editedAccount['url'] ?? '', 'userName': _editedAccount['username'] ?? '', 'password': _editedAccount['password'] ?? '', }; }); } } _isInit = false; }); } super.didChangeDependencies(); }
额外优化点:
- 在给
_initValues赋值时添加?? ''空值判断,防止Firestore字段不存在导致的null错误。 - 打印数据时直接输出
_editedAccount.data().toString(),不需要包裹Text组件。
这样修改后,当异步获取到数据并更新_initValues后,setState()会触发UI重建,表单字段就能正确加载预填数据了。
内容的提问来源于stack exchange,提问作者Deucal
相关产品推荐
相关产品推荐

