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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 01:57:50