web-dev-qa-db-fra.com

Déclenchement de l'événement initial dans le bloc

exemple_states:

abstract class ExampleState extends Equatable {
  const ExampleState();
}

class LoadingState extends ExampleState {
  //
}

class LoadedState extends ExampleState {
  //
}

class FailedState extends ExampleState {
  //
}

exemple_events:

abstract class ExampleEvent extends Equatable {
  //
}

class SubscribeEvent extends ExampleEvent {
  //
}

class UnsubscribeEvent extends ExampleEvent {
  //
}

class FetchEvent extends ExampleEvent {
  // 
}

exemple_bloc:

class ExampleBloc extends Bloc<ExampleEvent, ExampleState> {
  @override
  ExampleState get initialState => LoadingState();

  @override
  Stream<ExampleState> mapEventToState(
    ExampleEvent event,
  ) async* {
    if (event is SubscribeEvent) {
      //
    } else if (event is UnsubscribeEvent) {
      //
    } else if (event is FetchEvent) {
      yield LoadingState();
      try {
        // network calls
        yield LoadedState();
      } catch (_) {
        yield FailedState();
      }
    }
  }
}

exemple_screen:

class ExampleScreenState extends StatelessWidget {
  // ignore: close_sinks
  final blocA = ExampleBloc();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: BlocBuilder<ExampleBloc, ExampleState>(
        bloc: blocA,
        // ignore: missing_return
        builder: (BuildContext context, state) {
          if (state is LoadingState) {
            blocA.add(Fetch());
            return CircularProgressBar();
          }

          if (state is LoadedState) {
            //...
          }

          if (state is FailedState) {
            //...
          }
        },
      ),
    );
  }
}

Comme vous pouvez le constater dans Exemple_bloc, l'état initial est le chargement du chargement () et dans la construction indique une barre de progression circulaire. J'utilise l'événement Fetch () pour déclencher des états suivants. Mais je ne me sens pas à l'aise en utilisant là-bas. Ce que je veux faire, c'est:

Lorsque l'application démarre, il doit afficher le chargement de l'État et démarrer les appels de réseau, puis lorsqu'il est terminé, il devrait indiquer que LoquetState avec des résultats d'appel de réseautage et échoué si quelque chose ne va pas. Je veux y parvenir sans faire

if (state is LoadingState) {
  blocA.add(Fetch());
  return CircularProgressBar();
}
7
vendrick

Votre inconfort a vraiment raison - aucun événement ne doit être tiré de build() Méthode (Build () pourrait être tiré autant de fois que les besoins crocheurs)

Notre cas est d'incendier l'événement initial sur la création du Bloc

Possibilités d'aperçu

  1. cas avec insertion de bloc avec BlocProvider - c'est préféré

create: rappel est déclenché une seule fois lorsque BlocProvider est monté et BlocProvider fermerait () Bloc lorsque BlocProvider est démontré

    class ExampleScreenState extends StatelessWidget {
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: BlocProvider(
            create: (context) => ExampleBloc()..add(Fetch()), // <-- first event, 
            child: BlocBuilder<ExampleBloc, ExampleState>(
              builder: (BuildContext context, state) {
                ...
              },
            ),
          ),
        );
      }
    }
  1. cas lorsque vous créez un Bloc dans State de widget étatique
class _ExampleScreenStateState extends State<ExampleScreenState> {
  ExampleBloc _exampleBloc;

  @override
  void initState() {
    super.initState();
    _exampleBloc = ExampleBloc();
    _exampleBloc.add(Fetch());
    // or use cascade notation
    // _exampleBloc = ExampleBloc()..add(Fetch());
  }

  @override
  void dispose() {
    super.dispose();
    _exampleBloc.close(); // do not forget to close, prefer use BlocProvider - it would handle it for you
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: BlocBuilder<ExampleBloc, ExampleState>(
        bloc: _exampleBloc,
        builder: (BuildContext context, state) {
         ...
        },
      ),
    );
  }
}
  1. ajouter un premier événement sur la création de l'instance Bloc - cette manière a des inconvénients lors du test car le premier événement est implicite
class ExampleBloc extends Bloc<ExampleEvent, ExampleState> {

  ...

  ExampleBloc() {
    add(Fetch());
  }
}

// insert it to widget tree with BlocProvider or create in State
BlocProvider( create: (_) => ExampleBloc(), ...

// or in State

class _ExampleScreenStateState extends State<ExampleScreenState> {
  final _exampleBloc = ExampleBloc(); 
...

PS N'hésitez pas à me joindre à des commentaires

15
Sergey Salnikov