flutter\_bloc library increment decrement button using flutter bloc

Issue

I’m pretty new to flutter_bloc library and i’m trying to make component of increment decrement button but when I tried to duplicate the component, i face the problem, when I push the second increment button component the first component updated too like this result. I want them to have separated result. how can i fix that?

here is my bloc code:

import 'package:bloc/bloc.dart';

abstract class QtyEvent{}

class Increment extends QtyEvent {}

class Decrement extends QtyEvent {}

class QtyBloc extends Bloc<QtyEvent, int> {
  QtyBloc() : super(0) {
    on<Increment>((event, emit) >
      emit(state+1));
    on<Decrement>((event, emit) >
      emit(state-1));
  }
}

and here is my component code:

class _QtyState extends State<Qty> {
  int _n  0;
  @override
  void add() {
    setState(() {
      _n++;
    });
    context.read<QtyBloc>().add(Increment());
  }

  void minus() {
    setState(() {
      if (_n ! 0) _n--;
    });
    context.read<QtyBloc>().add(Decrement());
  }

  QtyBloc qtybloc  QtyBloc();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),), 
      body: Column(
        children: [
          Row(
            children: [
              GestureDetector(
                onTap: minus,
                child: Container(
                  padding: EdgeInsets.all(5),
                  decoration: BoxDecoration(
                      borderRadius: BorderRadius.circular(20),
                      color: Colors.red),
                  child: Icon(Icons.remove),
                ),
              ),
              Text(
                context.watch<QtyBloc>().state.toString(),
                style: TextStyle(fontSize: 20),
              ),
              GestureDetector(
                onTap: add,
                child: Container(
                  padding: EdgeInsets.all(5),
                  decoration: BoxDecoration(
                      borderRadius: BorderRadius.circular(20),
                      color: Colors.red),
                  child: Icon(Icons.add),
                ),
              ),
            ],
          ),
        ],
      ),
    );
  }
}

Solution

your code is doing exactly what it was designed to do.
If I understand correctly, you want to use the same Bloc to have two sets of increment & decrement buttons?

Since you are emitting a single state, when you update it in one place, it updates everywhere!

Also, you do not need to call setState as it re renders the UI which can be achieved by bloc it self.

And, in the heading you mentioned you use flutter_bloc but in your code, you are using bloc.

Flutter Bloc

Bloc

Here is how to implement it with flutter_bloc,

logic.dart

import 'package:flutter_bloc/flutter_bloc.dart';

class CounterEvent {
  const CounterEvent();
}

class Increment extends CounterEvent {
  final int value1, value2;
  const Increment({this.value1  1, this.value2  1});
}

class Decrement extends CounterEvent {
  final int value1, value2;
  const Decrement({this.value1  1, this.value2  1});
}

class Reset extends CounterEvent {
  final int value;
  const Reset({this.value  0});
}

class CounterState {
  final int s1, s2;                                       // Just maintain 2 values!
  const CounterState({required this.s1, required this.s2});
}

class CounterBloc extends Bloc<CounterEvent, CounterState> {
  CounterBloc(CounterState initialState) : super(initialState);

  @override
  Stream<CounterState> mapEventToState(CounterEvent event) async* {
    if (event is Increment) {
      yield CounterState(
          s1: state.s1 + event.value1, s2: state.s2 + event.value2);
    } else if (event is Decrement) {
      yield CounterState(
          s1: state.s1 - event.value1, s2: state.s2 - event.value2);
    } else if (event is Reset) {
      yield CounterState(s1: event.value, s2: event.value);
    }
  }
}

component_page.dart

class Component extends StatelessWidget {
  const Component({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Counter'),
      ),
      body: BlocBuilder<CounterBloc, CounterState>(
        builder: (context, state) {
          return Column(
            children: [
              Row(
                children: [
                  GestureDetector(
                    onTap: () {
                      BlocProvider.of<CounterBloc>(context)
                          .add(const Decrement(value1: 1, value2: 0));
                    },
                    child: Container(
                      padding: const EdgeInsets.all(5),
                      decoration: BoxDecoration(
                          borderRadius: BorderRadius.circular(20),
                          color: Colors.red),
                      child: const Icon(Icons.remove),
                    ),
                  ),
                  Text(
                    state.s1.toString(),
                    style: const TextStyle(fontSize: 20, color: Colors.white),
                  ),
                  GestureDetector(
                    onTap: () {
                      BlocProvider.of<CounterBloc>(context)
                          .add(const Increment(value1: 1, value2: 0));
                    },
                    child: Container(
                      padding: const EdgeInsets.all(5),
                      decoration: BoxDecoration(
                          borderRadius: BorderRadius.circular(20),
                          color: Colors.red),
                      child: const Icon(Icons.add),
                    ),
                  ),
                ],
              ),
              Row(
                children: [
                  GestureDetector(
                    onTap: () {
                      BlocProvider.of<CounterBloc>(context)
                          .add(const Decrement(value1: 0, value2: 1));
                    },
                    child: Container(
                      padding: const EdgeInsets.all(5),
                      decoration: BoxDecoration(
                          borderRadius: BorderRadius.circular(20),
                          color: Colors.red),
                      child: const Icon(Icons.remove),
                    ),
                  ),
                  Text(
                    state.s2.toString(),
                    style: const TextStyle(fontSize: 20, color: Colors.white),
                  ),
                  GestureDetector(
                    onTap: () {
                      BlocProvider.of<CounterBloc>(context)
                          .add(const Increment(value1: 0, value2: 1));
                    },
                    child: Container(
                      padding: const EdgeInsets.all(5),
                      decoration: BoxDecoration(
                          borderRadius: BorderRadius.circular(20),
                          color: Colors.red),
                      child: const Icon(Icons.add),
                    ),
                  ),
                ],
              ),
              Row(
                children: [
                  GestureDetector(
                    onTap: () {
                      BlocProvider.of<CounterBloc>(context)
                          .add(const Reset(value: 0));
                    },
                    child: Container(
                      padding: const EdgeInsets.all(5),
                      decoration: BoxDecoration(
                          borderRadius: BorderRadius.circular(20),
                          color: Colors.red),
                      child: const Icon(Icons.refresh),
                    ),
                  ),
                ],
              ),
            ],
          );
        },
      ),
    );
  }
} 

Note

  • This code is written with null safety
  • Remember to add BlocProvider around your app, like so:

main.dart

void main() async {
  runApp(const App());
}

class App extends StatelessWidget {
  const App({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return BlocProvider<CounterBloc>(
      create: (_) > CounterBloc(const CounterState(s1: 0, s2: 0)),
      child: const MaterialApp(
        debugShowCheckedModeBanner: false,
        home: Component(),
      ),
    );
  }
}

Answered By – Nithin Sai

Leave a Comment