问题描述
我们如何在 StreamBuilder 中添加 TextField?我有一个 TextField/TextFormField 作为 StreamBuilder 或 FutureBuilder 的构建器函数内的小部件之一,每当我们尝试与文本字段交互时,它只会刷新整个构建器小部件并再次调用流/未来.
How do we add a TextField inside a StreamBuilder?I have a TextField / TextFormField as one of the widgets inside the builder function of either a StreamBuilder or FutureBuilder, whenever we try to interact with the textfield it just refreshes the entire builder widget and calls the stream/future again.
body: StreamBuilder(
stream: getClientProfile().snapshots(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.active) {
print(snapshot.data.data);
Client tempClient = Client.from(snapshot.data);
print('details = ${tempClient.representative.email} ${tempClient
.address.location} ${tempClient.businessDescription}');
return Container(
child: Column(
children: <Widget>[
TextFormField(
)
],
),
);
} else if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
} else {
return Center(
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: Icon(Icons.error),
),
Text('Error loading data')
],
),
);
}
}),
和firestore函数
and firestore function
DocumentReference getClientProfile() {
return _firestore.collection(SELLERS_COLLECTION).document(_uid);
}
我想要实现的是拥有一个包含来自 firestore 文档的预填充数据的表单,基本上是一个编辑表单.有没有其他方法可以实现相同的目标,或者我在结构上做错了什么?
What I want to achieve, is to have a form with pre-filled data from firestore document, basically an edit form. Is there any other way I could achieve the same or am I doing something wrong structurally ?
建议修改后的代码.
import 'package:flutter/material.dart';
import 'Utils/globalStore.dart';
import 'models/client_model.dart';
import 'dart:async';
class EditProfileInformation extends StatefulWidget {
@override
EditProfileInformationState createState() {
return new EditProfileInformationState();
}
}
class EditProfileInformationState extends State<EditProfileInformation> {
Stream dbCall;
final myController = TextEditingController();
@override
void initState() {
// TODO: implement initState
super.initState();
dbCall = getClientProfile().snapshots();
myController.addListener(_printLatestValue);
}
_printLatestValue() {
print("Second text field: ${myController.text}");
}
@override
void dispose() {
myController.removeListener(_printLatestValue);
myController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
// key: _scaffoldKey,
appBar: AppBar(
title: Text(
'Edit profile',
style: TextStyle(),
),
),
body: StreamBuilder(
stream: dbCall,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.active) {
print(snapshot.data.data);
Client tempClient = Client.from(snapshot.data);
print('details = ${tempClient.representative.email} ${tempClient
.address.location} ${tempClient.businessDescription}');
return Container(
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
controller: myController,
),
)
],
),
);
} else if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
} else {
return Center(
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: Icon(Icons.error),
),
Text('Error loading data')
],
),
);
}
}),
floatingActionButton: FloatingActionButton(
onPressed: () {
},
child: Icon(Icons.done),
),
);
}
}
推荐答案
为了正确使用 StreamBuilder,您必须确保正在使用的流缓存在 State 对象上.虽然 StreamBuilder 可以正确处理从流中获取新事件,但接收全新的 Stream 将强制它完全重建.在您的情况下,getClientProfile().snapshots()
将在调用时创建一个全新的 Stream,破坏文本字段的所有状态.
In order to use a StreamBuilder correctly you must ensure that the stream you are using is cached on a State object. While StreamBuilder can correctly handle getting new events from a stream, receiving an entirely new Stream will force it to completely rebuild. In your case, getClientProfile().snapshots()
will create an entirely new Stream when it is called, destroying all of the state of your text fields.
class Example extends StatefulWidget {
@override
State createState() => new ExampleState();
}
class ExampleState extends State<Example> {
Stream<SomeType> _stream;
@override
void initState() {
// Only create the stream once
_stream = _firestore.collection(collection).document(id);
super.initState();
}
@override
Widget build(BuildContext context) {
return new StreamBuilder(
stream: _stream,
builder: (context, snapshot) {
...
},
);
}
}
听起来我无法从您提供的代码片段中诊断出其他问题.
it sounds like there are other problems which I cannot diagnose from the code snippet you provided.
这篇关于在 Streambuilder 中使用 TextField的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!