2

my UI consists of a table of objects Apples.
Every cell in the table:

  • has an ADD button, if the apple is NOT present for that cell
  • it shows the apple and has a DELETE button, if the apple is present

The main page of my application is calling the following widget to LOAD the LIST of apples from an API. And also the ADD and DELETE functions communicate with the same API for adding and deleting the apple.

class ApplesLoader extends StatefulWidget {
  @override
  _ApplesLoaderState createState() => _ApplesLoaderState();
}

class _ApplesLoaderState extends State<ApplesLoader> {
  @override
  void initState() {
    super.initState();
    BlocProvider.of<ApplesCubit>(context).getAll();
  }

  @override
  Widget build(BuildContext context) {
    return BlocConsumer<ApplesCubit, ApplesState>(
      listener: ...,
      builder: (ctx, state) {
        if (!(state is ApplesLoaded)) {
          return circularProgressIndicator;
        }
        return ApplesViewer(state.Apples);
      },
    );
  }
}

So after that ApplesViewerhas the list of apples and can correctly display the grid.

But now I have two problems:

  1. When I press the ADD button or the DELETE button, all the application is rebuilt, while I could actually just re-paint the cell. But I don't know how to avoid this, because I also need to communicate to the application that the list of apples is actually changed. I don't want to rebuild the entire UI because it seems inefficient since what is actually changing on my page is only the selected cell.

  2. When I press the ADD button or the DELETE button, I would like to show a circular progress indicator that replaces the button (while waiting for the API to actually creating/deleting the apple). But when the list changes, all the application is rebuilt instead. So, I am not sure how to achieve this desired behavior.

Could you help me in solving those two issues?
Or advise me for a change of infrastructure in case I am making some mistake in dealing with this?

If needed, this is the code for ApplesCubit

class ApplesCubit extends Cubit<ApplesState> {
  final ApplesRepository _repository;

  ApplesCubit(this._repository) : super(ApplesLoading());

  Future<void> getAll() async {
    try {
      final apples = await _repository.getAll();
      emit(ApplesLoaded(List<Apple>.from(apples)));
    } on DataError catch (e) {
      emit(ApplesError(e));
    }
  }

  Future<void> create(List<Apple> apples, Apple appleToAdd) async {
    try {
      final newApple = await _repository.create(appleToAdd);
      final updatedApples = List<Apple>.from(apples)..add(newApple);
      emit(ApplesLoaded(updatedApples));
    } on DataError catch (e) {
      emit(ApplesError(e));
    }
  }

  Future<void> delete(List<Apple> Appless, Apple appleToDelete) async {
    try {
      await _repository.deleteApples(appleToDelete);
      final updatedApples = List<Apple>.from(Appless)..remove(appleToDelete);
      emit(ApplesLoaded(updatedApples));
    } on DataError catch (e) {
      emit(ApplesError(e));
    }
  }
}
  • Can you add some more context why you don't want to rebuilt the UI and why you want a progress indicator? Since adding a and removing from a list should be instant, it does not make any sense. If for some reason it is *not* instant, it would be good to know where the waiting occurs to suggest a solution. – nvoigt Mar 05 '21 at 11:29
  • Do you think is it clear enough now @nvoigt? Do you have some tips on how to improve the question, even more, it seems no one it is replying to it. – Federico Conte Mar 09 '21 at 14:26
  • The fact that u should use copyWith as below: https://stackoverflow.com/a/66259281/2473719 – Thang PhamVan Dec 07 '21 at 18:07
  • @FedericoConte is this question still valid because I implemented a lot of such lists but writing the answers down takes some effort ;) – novas1r1 Dec 22 '21 at 11:33

0 Answers0