如何保持旧数据处于相同状态,同时使用不同数据发出相同状态,并在 UI 中使用不同的 blocBuilder 分别渲染它们

发布于 2025-01-19 01:57:51 字数 5828 浏览 2 评论 0原文

我有一个名为specialityBloc 的块,它将根据医生的专业从firestore 中获取医生,并将其委托给存储库。

问题是当我想获取具有不同专业的不同医生并从同一状态(fetchSuccessState)发出它们时。

我可以从 firestore 中单独获取它们,但是当涉及到使用不同的块构建器(监听相同的specialityBloc)在 UI 中渲染时。它会覆盖旧数据(在第一个 Api 调用中)并将其替换为后续 api 调用的结果。

我想保留旧的状态并渲染它的 UI,并渲染它下面的新数据(从相同的状态发出)。

这是我的专业块

  SpecialityBloc() : super(InitialState()){
    on<GetSpeciality>((event, emit) async {
      emit(WaitingSpeciality());
      try{
        final data = await FirebaseRepo.getDoctorsBySpeciality(event.speciality);
        data.fold((l){
          emit(GetSpecialitySuccess(doctors:l));
        }, (r){
          
        });
      }catch(e){
        print(e);
      }
    });
  }
  
}

abstract class SpecialityState extends Equatable {

}

abstract class SpecialityEvent {

}

class InitialState extends SpecialityState {
@override
  List<Object> get props => [];
}

class WaitingSpeciality extends SpecialityState {
  @override
  List<Object> get props => [];

}

class GetSpecialitySuccess extends SpecialityState {
final List<DoctorModel> doctors;
GetSpecialitySuccess({required this.doctors});
@override
  List<Object> get props => [doctors];
}

class GetSpeciality extends SpecialityEvent {

  final String speciality;
  GetSpeciality(this.speciality);

}```

This is the UI part

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:patient_app/ui/screens/home/home_bloc/popular_bloc.dart';
import 'package:patient_app/ui/screens/home/home_bloc/speciality_bloc.dart';
import 'package:patient_app/ui/widgets/gridViewLoading.dart';
import 'package:shimmer/shimmer.dart';
import 'package:patient_app/ui/screens/home/home_bloc/home_bloc.dart';
import 'package:patient_app/ui/widgets/custom_carousel.dart';
import 'package:patient_app/ui/widgets/search_bar.dart';
import 'package:patient_app/ui/widgets/square.dart';
import 'package:patient_app/ui/widgets/username.dart';

class Home extends StatefulWidget {
  const Home({ Key? key }) : super(key: key);

  @override
  State<Home> createState() => _HomeState();
}

class _HomeState extends State<Home> {

  @override
  void initState() {
    super.initState();

    context.read<HomeBloc>().add(GetUserInfo());
    context.read<PopularBloc>().add(GetPopularDoctors());
    context.read<SpecialityBloc>().add(GetSpeciality('paediatrics'));
    context.read<SpecialityBloc>().add(GetSpeciality('gynaecologist'));
  }

  @override
  Widget build(BuildContext context) {
    return   SingleChildScrollView(
          child: Padding(
            padding: const EdgeInsets.only(left:20.0,right: 20,),
            child: Column(

              children: [
                const SizedBox(height: 35,),
                BlocBuilder<HomeBloc,HomeState>(
                  
                  builder: (ctx,state){
                    if(state is Waiting){
                      return Align(
                        alignment: Alignment.centerLeft,
                        child: Shimmer.fromColors(
                          baseColor: Colors.amber,
                          highlightColor: Colors.grey[300]!,
                          child: Container(
                            decoration: BoxDecoration(
                              borderRadius: BorderRadius.circular(10),
                              color: Colors.amber,
                            ),
                            height: 20,width: 150,),
                        ));
                    }
                    if(state is Success){
                      return UserName(name: state.data.name!);
                    }
                    else{
                      return Container();
                    }
                    
                  },
                ),
                CustomCarousel(slides: [
                  SizedBox(
                    width: double.infinity,
                    child: Image.network("https://cdn.pixabay.com/photo/2020/09/13/20/24/doctor-5569298_960_720.png",fit: BoxFit.cover,),
                  ),
                  SizedBox(
                    width: double.infinity,
                    child: Image.network("https://cdn.pixabay.com/photo/2021/11/20/03/16/doctor-6810750_960_720.png",fit: BoxFit.cover,),
                  ),
                ]),
                const SearchBar(),
                
                BlocBuilder<PopularBloc,PopularState>(builder: (ctx,state){
                  if(state is WaitingPopular){
                    return const GridViewLoading();
                  }
                  if(state is PopularDoctorsSuccess){
                   
                    return Square(doctors: state.doctors,title: "Popular Doctors",);
                  }
                  return Container();
                }),
               
                
                BlocBuilder<SpecialityBloc,SpecialityState>(builder: (ctx,state){

                  if(state is WaitingSpeciality){
                    return const GridViewLoading();
                  }
                  if(state is GetSpecialitySuccess){
                    return Square(doctors: state.doctors,title: " Paediatrics",);
                  }
                  return Container();

                }),

                BlocBuilder<SpecialityBloc,SpecialityState>(builder: (ctx,state){

                  if(state is WaitingSpeciality){
                    return const GridViewLoading();
                  }
                  if(state is GetSpecialitySuccess){
                    return Square(doctors: state.doctors,title: "Gynaecologist",);
                  }
                  return Container();

                })
                
              ],
            ),
          ),
        );
  }
}


I have a bloc called specialityBloc which will fetch doctors according to their speciality from firestore by delegating it to a repository.

The problem is when I want to fetch different doctors with different speciality and emit them from same state(fetchSuccessState).

I am able to fetch them separately from firestore but when It comes to rendering in the UI using different bloc builders(that listen to the same specialityBloc).It overrides the old data(which was there in the first Api call) and replaces it with the result of the subsequent api calls.

I want to keep the old the in the state and render it UI and also render the new Data below it(which was emitted from the same state).

Here is my Specialitybloc

  SpecialityBloc() : super(InitialState()){
    on<GetSpeciality>((event, emit) async {
      emit(WaitingSpeciality());
      try{
        final data = await FirebaseRepo.getDoctorsBySpeciality(event.speciality);
        data.fold((l){
          emit(GetSpecialitySuccess(doctors:l));
        }, (r){
          
        });
      }catch(e){
        print(e);
      }
    });
  }
  
}

abstract class SpecialityState extends Equatable {

}

abstract class SpecialityEvent {

}

class InitialState extends SpecialityState {
@override
  List<Object> get props => [];
}

class WaitingSpeciality extends SpecialityState {
  @override
  List<Object> get props => [];

}

class GetSpecialitySuccess extends SpecialityState {
final List<DoctorModel> doctors;
GetSpecialitySuccess({required this.doctors});
@override
  List<Object> get props => [doctors];
}

class GetSpeciality extends SpecialityEvent {

  final String speciality;
  GetSpeciality(this.speciality);

}```

This is the UI part

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:patient_app/ui/screens/home/home_bloc/popular_bloc.dart';
import 'package:patient_app/ui/screens/home/home_bloc/speciality_bloc.dart';
import 'package:patient_app/ui/widgets/gridViewLoading.dart';
import 'package:shimmer/shimmer.dart';
import 'package:patient_app/ui/screens/home/home_bloc/home_bloc.dart';
import 'package:patient_app/ui/widgets/custom_carousel.dart';
import 'package:patient_app/ui/widgets/search_bar.dart';
import 'package:patient_app/ui/widgets/square.dart';
import 'package:patient_app/ui/widgets/username.dart';

class Home extends StatefulWidget {
  const Home({ Key? key }) : super(key: key);

  @override
  State<Home> createState() => _HomeState();
}

class _HomeState extends State<Home> {

  @override
  void initState() {
    super.initState();

    context.read<HomeBloc>().add(GetUserInfo());
    context.read<PopularBloc>().add(GetPopularDoctors());
    context.read<SpecialityBloc>().add(GetSpeciality('paediatrics'));
    context.read<SpecialityBloc>().add(GetSpeciality('gynaecologist'));
  }

  @override
  Widget build(BuildContext context) {
    return   SingleChildScrollView(
          child: Padding(
            padding: const EdgeInsets.only(left:20.0,right: 20,),
            child: Column(

              children: [
                const SizedBox(height: 35,),
                BlocBuilder<HomeBloc,HomeState>(
                  
                  builder: (ctx,state){
                    if(state is Waiting){
                      return Align(
                        alignment: Alignment.centerLeft,
                        child: Shimmer.fromColors(
                          baseColor: Colors.amber,
                          highlightColor: Colors.grey[300]!,
                          child: Container(
                            decoration: BoxDecoration(
                              borderRadius: BorderRadius.circular(10),
                              color: Colors.amber,
                            ),
                            height: 20,width: 150,),
                        ));
                    }
                    if(state is Success){
                      return UserName(name: state.data.name!);
                    }
                    else{
                      return Container();
                    }
                    
                  },
                ),
                CustomCarousel(slides: [
                  SizedBox(
                    width: double.infinity,
                    child: Image.network("https://cdn.pixabay.com/photo/2020/09/13/20/24/doctor-5569298_960_720.png",fit: BoxFit.cover,),
                  ),
                  SizedBox(
                    width: double.infinity,
                    child: Image.network("https://cdn.pixabay.com/photo/2021/11/20/03/16/doctor-6810750_960_720.png",fit: BoxFit.cover,),
                  ),
                ]),
                const SearchBar(),
                
                BlocBuilder<PopularBloc,PopularState>(builder: (ctx,state){
                  if(state is WaitingPopular){
                    return const GridViewLoading();
                  }
                  if(state is PopularDoctorsSuccess){
                   
                    return Square(doctors: state.doctors,title: "Popular Doctors",);
                  }
                  return Container();
                }),
               
                
                BlocBuilder<SpecialityBloc,SpecialityState>(builder: (ctx,state){

                  if(state is WaitingSpeciality){
                    return const GridViewLoading();
                  }
                  if(state is GetSpecialitySuccess){
                    return Square(doctors: state.doctors,title: " Paediatrics",);
                  }
                  return Container();

                }),

                BlocBuilder<SpecialityBloc,SpecialityState>(builder: (ctx,state){

                  if(state is WaitingSpeciality){
                    return const GridViewLoading();
                  }
                  if(state is GetSpecialitySuccess){
                    return Square(doctors: state.doctors,title: "Gynaecologist",);
                  }
                  return Container();

                })
                
              ],
            ),
          ),
        );
  }
}


如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

山有枢 2025-01-26 01:57:51

如果我没猜错的话,您是在尝试保存从 API 获得的旧结果以便稍后使用,对吧?
如果是这样那么:
你可以尝试让你的 var 成为一个全局变量,然后当数据到来时,你可以分配你在这个变量中获得的数据,以便稍后在类似的另一个状态中使用它

late final data;
//or the other way you can make data as a list here
//of the type object you are using ex Doctor or so..



SpecialityBloc() : super(InitialState()){
    on<GetSpeciality>((event, emit) async {
      emit(WaitingSpeciality());
      try{
        data = await FirebaseRepo.getDoctorsBySpeciality(event.speciality);
        data.fold((l){
          emit(GetSpecialitySuccess(doctors:l));
        }, (r){
          
        });
      }catch(e){
        print(e);
      }
    });
  }
// now you can use your data variable that has the info with any other state or with whatever you want 

,每次只需将它们添加到你的列表中,然后你就可以得到返回到列表中您想要的任何对象,例如使用某个 ID 搜索医生,如果它不在列表中,您可以获取它并将其再次添加到列表中,在这里您可以使用相同的状态来渲染不同的对象,还尝试从代码中删除 equatable 并如果您确实不需要它,请尝试不使用它。

if I got you correctly you are trying to save the old result that you got from the API to use it later on right ?
if so then :
you can try to make you var a global variable and then when the data comes you can assign the data you got in this variable to use it later on in another state like that

late final data;
//or the other way you can make data as a list here
//of the type object you are using ex Doctor or so..



SpecialityBloc() : super(InitialState()){
    on<GetSpeciality>((event, emit) async {
      emit(WaitingSpeciality());
      try{
        data = await FirebaseRepo.getDoctorsBySpeciality(event.speciality);
        data.fold((l){
          emit(GetSpecialitySuccess(doctors:l));
        }, (r){
          
        });
      }catch(e){
        print(e);
      }
    });
  }
// now you can use your data variable that has the info with any other state or with whatever you want 

and just add them to your list each time and then you can get back to whatever object you want from the list like maybe search for an a doctor using some ID and if it's not in the list you can fetch it and add it again to the list and here you can use the same state to render a different object, also try to remove the equatable from your code and try without it if you don't really need it.

情独悲 2025-01-26 01:57:51

如果我做对了,最简单和正确的方法是让不同的事件为每个专业返回不同的状态,同时作用于 UI 上的相同或不同的构建器;基于块构建器的 buildWhen 方法。在内部,您可以编写一个可重用的方法来执行 API 查询,每次使用不同的事件(特殊)触发它,并且它可以根据方法调用者发出相应的状态。

优点:更好地控制 UI 和更好的可测试性。

If I am getting it right, the simplest and the right approach would be to have different events returning different states for each specialty, while acting on the same or different builders on the UI; based on buildWhen method of the bloc builder. Internally you can write a reusable method which does the API query, trigger it each time with a different event (specialty) and it can emit a respective state based on the method caller.

Benefits: better control on the UI and better testability.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文