Firebase SetState导致Futurebuilder在每次点击时重新加载数据

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的状态。我想要的只是更改每次单击时的图标状态,而不是从数据库获取整个数据 这是初始状态 当我点击收藏夹图标时,假设我点击了第一个图标,然后它开始加载。 然后所有图标都会更改:( 我只想改变点击图标的状态,不是所有的图

我正在使用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对象中共享相同的状态。解决这一问题的一种方法是给它们自己的状态。您只需要