Firebase SetState导致Futurebuilder在每次点击时重新加载数据
我正在使用future builder和stream builder从firebase获取数据并在屏幕上显示它们。 我也有最喜欢的按钮。当我点击最喜爱的按钮时。它从firebase获取数据,然后将状态更改为最喜爱的图标按钮。 它还可以更改其他每个listview.Builder的状态。我想要的只是更改每次单击时的图标状态,而不是从数据库获取整个数据 这是初始状态 当我点击收藏夹图标时,假设我点击了第一个图标,然后它开始加载。 然后所有图标都会更改:( 我只想改变点击图标的状态,不是所有的图标,也不想点击获取数据,只想改变按钮的状态。下面是代码Firebase SetState导致Futurebuilder在每次点击时重新加载数据,firebase,flutter,dart,firebase-realtime-database,google-cloud-firestore,Firebase,Flutter,Dart,Firebase Realtime Database,Google Cloud Firestore,我正在使用future builder和stream builder从firebase获取数据并在屏幕上显示它们。 我也有最喜欢的按钮。当我点击最喜爱的按钮时。它从firebase获取数据,然后将状态更改为最喜爱的图标按钮。 它还可以更改其他每个listview.Builder的状态。我想要的只是更改每次单击时的图标状态,而不是从数据库获取整个数据 这是初始状态 当我点击收藏夹图标时,假设我点击了第一个图标,然后它开始加载。 然后所有图标都会更改:( 我只想改变点击图标的状态,不是所有的图
class TalentScreen1 extends StatefulWidget {
@override
_TalentScreen1State createState() => _TalentScreen1State();
}
class _TalentScreen1State extends State<TalentScreen1> {
bool toggle = false;
@override
Widget build(BuildContext context) {
return BlocProvider<TalentFavCubit>(
create: (context) => TalentFavCubit(),
child: SafeArea(
child: Scaffold(
body: Padding(
padding: const EdgeInsets.all(20.0),
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Text('Talent Screen 1 home search'),
_retriveAllDocs,
],
),
),
),
),
),
);
}
Widget get _retriveAllDocs => FutureBuilder<QuerySnapshot>(
future: FirebaseRepo.instance.fetchWorkerFormFieldsData(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting)
return CircularProgressIndicator();
if (snapshot.hasError) {
return Text("Something went wrong");
}
if (!snapshot.hasData) {
return Text("Nothing to show");
}
if (snapshot.connectionState == ConnectionState.done) {
final List<DocumentSnapshot> data = snapshot.data.docs;
return theUserInfo(data);
}
return Text("loading");
});
Widget theUserInfo(List<DocumentSnapshot> data) {
return ListView.builder(
shrinkWrap: true,
itemCount: data.length,
itemBuilder: (context, index) {
return FutureBuilder<DocumentSnapshot>(
future: fetch(data[index]['uid']),
builder: (BuildContext context,
AsyncSnapshot<DocumentSnapshot> snapshot) {
if (snapshot.hasError) {
return Text("Something went wrong");
}
if (snapshot.connectionState == ConnectionState.done) {
TalentHireFavModel userData = TalentHireFavModel.fromMap(
data[index].data(), snapshot.data.data());
return Card(
child: Column(
children: <Widget>[
Text(userData.name),
Text(userData.categories),
Text(userData.skills),
Text(userData.country),
Text(userData.phoneNo),
Text(userData.hourlyRate),
Text(userData.professionalOverview),
Text(userData.skills),
Text(userData.expert),
Text(userData.createdAt),
IconButton(
icon: toggle
? Icon(Icons.favorite_border)
: Icon(
Icons.favorite,
),
onPressed: () {
setState(() {
// Here we changing the icon.
toggle = !toggle;
});
}),
],
),
);
}
return Container();
});
});
}
//TODO: Implementation Fix Error
Widget _iconButton(uid) {
return StreamBuilder<QuerySnapshot>(
stream: FirebaseRepo.instance.fetchCurrentUserFavourites().snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
var data = snapshot.data.docs;
// print(snapshot.data.get('uid'));
if (snapshot.hasError) {
return Text('Something went wrong');
}
return IconButton(
icon: data.isEmpty == uid
? Icon(Icons.favorite)
: Icon(Icons.favorite_border),
onPressed: () =>
BlocProvider.of<TalentFavCubit>(context).addTalentFav(uid));
},
);
}
Future<DocumentSnapshot> fetch(data) async =>
await FirebaseRepo.instance.fetchWorkerUserData(data);
}
class TalentScreen1扩展StatefulWidget{
@凌驾
_TalentScreen1State createState()=>_TalentScreen1State();
}
类_TalentScreen1State扩展状态{
bool-toggle=false;
@凌驾
小部件构建(构建上下文){
返回BlocProvider(
create:(context)=>TalentFavCubit(),
儿童:安全区(
孩子:脚手架(
主体:填充物(
填充:常数边集全部(20.0),
子:SingleChildScrollView(
子:列(
mainAxisAlignment:mainAxisAlignment.start,
儿童:[
文本(“人才屏幕1主页搜索”),
_检索所有文档,
],
),
),
),
),
),
);
}
Widget get\u RetrieveAllDocs=>FutureBuilder(
future:FirebaseRepo.instance.fetchWorkerFormFieldsData(),
生成器:(BuildContext上下文,异步快照){
if(snapshot.connectionState==connectionState.waiting)
返回循环ProgressIndicator();
if(snapshot.hasError){
返回文本(“出错”);
}
如果(!snapshot.hasData){
返回文本(“无需显示”);
}
if(snapshot.connectionState==connectionState.done){
最终列表数据=snapshot.data.docs;
返回用户信息(数据);
}
返回文本(“加载”);
});
小部件用户信息(列表数据){
返回ListView.builder(
收缩膜:对,
itemCount:data.length,
itemBuilder:(上下文,索引){
回归未来建设者(
未来:获取(数据[索引]['uid']),
生成器:(BuildContext上下文,
异步快照(快照){
if(snapshot.hasError){
返回文本(“出错”);
}
if(snapshot.connectionState==connectionState.done){
TalentHireFavModel userData=TalentHireFavModel.fromMap(
数据[索引].data(),快照.data.data());
回程卡(
子:列(
儿童:[
文本(userData.name),
文本(userData.categories),
文本(userData.skills),
文本(userData.country),
文本(userData.phoneNo),
文本(userData.hourlyRate),
文本(userData.professionalOverview),
文本(userData.skills),
文本(userData.expert),
文本(userData.createdAt),
图标按钮(
图标:切换
?图标(图标、最喜爱的边框)
:图标(
我的最爱,
),
已按下:(){
设置状态(){
//我们在这里更改图标。
切换=!切换;
});
}),
],
),
);
}
返回容器();
});
});
}
//TODO:实现修复错误
小部件图标按钮(uid){
返回流生成器(
流:FirebaseRepo.instance.FetchCurrentUserFavorites().snapshots(),
生成器:(BuildContext上下文,异步快照){
var data=snapshot.data.docs;
//打印(snapshot.data.get('uid');
if(snapshot.hasError){
返回文本(“出错”);
}
返回图标按钮(
图标:data.isEmpty==uid
?图标(图标。收藏夹)
:图标(图标。收藏夹边框),
按下:()=>
BlocProvider.of(context.addTalentFav(uid));
},
);
}
未来提取(数据)异步=>
等待FirebaseRepo.instance.fetchWorkerUserData(数据);
}
这是您的断线代码:
future: FirebaseRepo.instance.fetchWorkerFormFieldsData(),
FutureBuilder文档从以下内容开始:
未来必须在更早的时候获得,例如在State.initState、State.didUpdateWidget或State.didChangeDependencies期间。在构造FutureBuilder时,不能在State.build或无状态Widget.build方法调用期间创建未来。如果未来与FutureBuilder同时创建,则每次FutureBuilder如果重新生成其父级,则将重新启动异步任务
一般的指导原则是假设每个构建方法在每一帧都可以被调用,并将省略的调用视为一种优化
你违反了合同。我有一段视频详细说明了这一点
照文档所说的做。TL;DR:不要在FutureBuilder的参数中创建Future。它们的状态会同时更改,因为它们都在相同的StatefulWidget中,或者它们在state对象中共享相同的状态。解决这一问题的一种方法是给它们自己的状态。您只需要