简体   繁体   中英

How to manage different States in the same Bloc? Flutter

I am trying to handle 3 different states in my app, in the initState of my home, I call the event "OnInitial" pretending to be a method that fetches data from the local DB.

As you can see in the method on I am setting "6" to the variable "number" as I said, pretending that this would be the data that I brought from the DB. My event finishes fetching the data and emits the state "ProductsTercero" already with "the data assigned".

In my home, if the state is ProductsTercero I paint a column with the "msg" and the "number". When inital finishes my screen is redrawn correctly and shows

在此处输入图像描述

But my problem is the following. When I press the button called "Tercero" that triggers the event "OnTercero" In my Bloc, when this event is called, it sets a 'New msg' to the variable "msg" of ProducsTercero. What does this? the next:

在此处输入图像描述

It removes the "number 6" that I had set before, that is, regarding the simulation, I would be deleting all the data that I brought from the DB.

my expected result was:

New msg
6

but i got

New msg
0

I debug and it seems like it's always creating a new ProductsThird object. even if I do ProductsTercero().copyWith(msg: 'New msg'); is the same.

I have worked with only 1 state and this does not happen to me, because I always do a state.copyWith(); and the other values of that state are always maintained no matter if i pass 1 attribute of 5 attributes it has. but here, having more than one state and having an abstract state class, I can't write emit(state.copyWith(msg: 'New msg');

What am I doing wrong? What would be the correct way to emit on X state and that this does not happen?

Event, state and bloc code:

part of 'products_bloc.dart';

@immutable
abstract class ProductsEvent {}

class OnInitial extends ProductsEvent {}
class OnSegundo extends ProductsEvent {}
class OnTercero extends ProductsEvent {}

//**************************************************************//

part of 'products_bloc.dart';

@immutable
abstract class ProductsState {}

class ProductsInitial extends ProductsState {
  final String? msg;
  final int? numero;

  ProductsInitial({numero, msg})
      : msg = msg ?? 'MSG: Default Inicial',
        numero = numero ?? 0;
  ProductsInitial copywith({String? msg, int? numero}) =>
      ProductsInitial(msg: msg ?? this.msg, numero: numero ?? this.numero);
}

class ProductsSegundo extends ProductsState {
  final String? msg;
  final int? numero;

  ProductsSegundo({numero, msg})
      : msg = msg ?? 'Second: Default Msg',
        numero = numero ?? 0;
  ProductsSegundo copywith({String? msg, int? numero}) =>
      ProductsSegundo(msg: msg ?? this.msg, numero: numero ?? this.numero);
}

class ProductsTercero extends ProductsState {
  final String? msg;
  final int? numero;

  ProductsTercero({numero, msg})
      : msg = msg ?? 'Third: Default Msg',
        numero = numero ?? 0;
  ProductsTercero copywith({String? msg, int? numero}) =>
      ProductsTercero(msg: msg ?? this.msg, numero: numero ?? this.numero);
}


//**********************************************************//

import 'package:bloc/bloc.dart';
import 'package:meta/meta.dart';

part 'products_event.dart';
part 'products_state.dart';

class ProductsBloc extends Bloc<ProductsEvent, ProductsState> {
  ProductsBloc() : super(ProductsInitial()) {
    on<OnInitial>((event, emit) {
      emit(ProductsInitial().copywith(
        msg: 'Initial msg'
      ));
      emit(ProductsTercero(numero: 6));
    });


    on<OnSegundo>((event, emit) {
      emit(ProductsSegundo());
    });


    on<OnTercero>((event, emit) {
      emit(ProductsTercero(msg: 'New msg'));
    });
  }
}

Homepage code:

import 'package:bloc_test/src/bloc/products/products_bloc.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

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

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {

  @override
  void initState() {
    BlocProvider.of<ProductsBloc>(context).add(OnInitial());
    super.initState();
  }
  @override
  Widget build(BuildContext context) {
    return BlocBuilder<ProductsBloc, ProductsState>(
      builder: (context, state) {
        return Scaffold(
          body: Column(
            crossAxisAlignment: CrossAxisAlignment.center,
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              (state is ProductsInitial) ? Column(
                children: [
                  Center(child: Text(state.msg!)),
                  Center(child: Text(state.numero!.toString())),
                ],
              )
              : (state is ProductsSegundo) ? Column(
                children: [
                  Center(child: Text(state.msg!)),
                  Center(child: Text(state.numero!.toString())),
                ],
              )
              : (state is ProductsTercero) ? Column(
                children: [
                  Center(child: Text(state.msg!)),
                  Center(child: Text(state.numero!.toString())),
                ],
              )
              : Center(child: Text('Nada')),
              SizedBox(
                height: 40,
                width: double.infinity,
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.spaceAround,
                  children: <Widget>[
                    ElevatedButton(
                        onPressed: () {
                          BlocProvider.of<ProductsBloc>(context).add(OnInitial());
                        },
                        child: Text('Initial')),
                    ElevatedButton(
                        onPressed: () {
                          BlocProvider.of<ProductsBloc>(context).add(OnSegundo());
                        },
                        child: Text('Segundo')),
                    ElevatedButton(
                        onPressed: () {
                          BlocProvider.of<ProductsBloc>(context).add(OnTercero());
                        },
                        child: Text('Tercero'))
                  ],
                ),
              ),
            ],
          ),
        );
      },
    );
  }
}

You are not passing num value on emit(ProductsTercero(msg: 'New msg'));

Since num == null then it is set to 0, as defined by your code.

Try Replacing like below

on<OnTercero>((event, emit) {
  emit(ProductsTercero(msg: 'New msg',numero: 6));
});

You are creating a new state object with each event. You want to copy the existing state.

on<OnTercero>((event, emit) {
   emit(state.copyWith(msg: 'New msg'));
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM