Top

Up

Recipes: Show SnakeBar with BlocListener

원문: Bloc / Recipes / Flutter / Show SnackBar

한국어로 번역은 현재 진행중입니다.

In this recipe, we’re going to take a look at how to use BlocListener to show a SnackBar in response to a state change in a bloc.

demo

Bloc

Let’s build a basic DataBloc which will handle DataEvents and output DataStates.

DataEvent

For simplicity, our DataBloc will only respond to a single DataEvent called FetchData.

import 'package:meta/meta.dart';

@immutable
abstract class DataEvent {}

class FetchData extends DataEvent {}

DataState

Our DataBloc can have one of three different DataStates:

import 'package:meta/meta.dart';

@immutable
abstract class DataState {}

class Initial extends DataState {}

class Loading extends DataState {}

class Success extends DataState {}

DataBloc

Our DataBloc should look something like this:

import 'package:bloc/bloc.dart';

class DataBloc extends Bloc<DataEvent, DataState> {
  @override
  DataState get initialState => Initial();

  @override
  Stream<DataState> mapEventToState(
    DataEvent event,
  ) async* {
    if (event is FetchData) {
      yield Loading();
      await Future.delayed(Duration(seconds: 2));
      yield Success();
    }
  }
}

Note: We’re using Future.delayed to simulate latency.

UI Layer

Now let’s take a look at how to hook up our DataBloc to a widget and show a SnackBar in response to a success state.

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return BlocProvider(
      bloc: DataBloc(),
      child: MaterialApp(
        home: Home(),
      ),
    );
  }
}

class Home extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Home')),
      body: BlocListener(
        bloc: BlocProvider.of<DataBloc>(context),
        listener: (BuildContext context, DataState state) {
          if (state is Success) {
            Scaffold.of(context).showSnackBar(
              SnackBar(
                backgroundColor: Colors.green,
                content: Text('Success'),
              ),
            );
          }
        },
        child: BlocBuilder(
          bloc: BlocProvider.of<DataBloc>(context),
          builder: (BuildContext context, DataState state) {
            if (state is Initial) {
              return Center(child: Text('Press the Button'));
            }
            if (state is Loading) {
              return Center(child: CircularProgressIndicator());
            }
            if (state is Success) {
              return Center(child: Text('Success'));
            }
          },
        ),
      ),
      floatingActionButton: Column(
        crossAxisAlignment: CrossAxisAlignment.end,
        mainAxisAlignment: MainAxisAlignment.end,
        children: <Widget>[
          FloatingActionButton(
            child: Icon(Icons.play_arrow),
            onPressed: () {
              BlocProvider.of<DataBloc>(context).dispatch(FetchData());
            },
          ),
        ],
      ),
    );
  }
}

We use the BlocListener widget in order to DO THINGS in response to state changes in our DataBloc.

We use the BlocBuilder widget in order to RENDER WIDGETS in response to state changes in our DataBloc.

We should NEVER “do things” in response to state changes in the builder method of BlocBuilder because that method can be called many times by the Flutter framework. The builder method should be a pure function that just returns a widget in response to the state of the bloc.

The full source for this recipe can be found here.


이전: Github Search

다음: Navigation