BlocBuilder的用途非常好理解,就是當Bloc的State有變化,他會根據你的設計重建App的介面。使用BlocBuilder就不再需要使用setState()
幫我們重繪介面了,一切交由BlocBuilder幫我們處理。
使用BlocBuilder需要給予兩個參數bloc
和builder
。同樣用LoginBloc作為範例。
BlocBuilder<LoginBloc, LoginState>(
builder: (BuildContext context, LoginState state) {
// 判斷目前的State是哪種,顯示對應的畫面給使用者
if(state.isSuccess) {
return Text('Login Successfully!');
}
else if (state.isFailure){
return Text('Login failed ><');
}
}
)
另外還有condition
參數能作使用,讓你能夠依照先前和當下的State決定是否要重新建構畫面。
BlocBuilder<LoginBloc, LoginState>(
condition: (previousState, currentState){
// 依照需求可以設定重建畫面的條件
// 回傳true會呼叫builder重建畫面
// 回傳false就會略過
}
builder: (BuildContext context, LoginState state) {
if(state.isSuccess){
return Text('Login Successfully!');
}
else if (state.isFailure){
return Text('Login failed ><');
}
}
)
BlocProvider顧名思義他的工作就是負責供應Bloc給其他人。它可以將Bloc給他widget tree下的children使用。這個widget非常方便,因為假如你不是使用它而是要自己實作bloc你會需要建立「inheritedwidget」才可以讓其他widget使用同個bloc。
如何實作inheritedwidget可以看這篇medium。
另外使用BlocProvider的優點就是它會自動幫你將Bloc關閉(dispose),避免記憶體洩漏的問題,你會發覺有BlocProvider處理這些瑣事真好。
BlocProvider(
builder: (BuildContext context) => LoginBloc(),
child: // 下面的widget就可以使用loginbloc
)
// 需要使用到Loginbloc的widget就可以用下面這行來呼叫
_loginBloc = BlocProvider.of<LoginBloc>(context);
如果有多個Bloc就可以使用MultiBlocProvider。
MultiBlocProvider(
providers: [
BlocProvider<BlocA>(
builder: (BuildContext context) => BlocA(),
),
BlocProvider<BlocB>(
builder: (BuildContext context) => BlocB(),
),
BlocProvider<BlocC>(
builder: (BuildContext context) => BlocC(),
),
],
child: ChildA(),
)
BlocListener和BlocBuilder類似一樣會去監聽State的變化,兩者的差別在於Listener是用來顯示如SnackBar、Dialog的通知,而Builder是重建整個畫面。
BlocListener<LoginBloc, LoginState>(
listener: (BuildContext context, LoginState state) {
// 如果登入失敗就顯示失敗的通知
if (state.isFailure) {
Scaffold.of(context)
..hideCurrentSnackBar()
..showSnackBar(SnackBar(
content: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text('Login Failure'), Icon(Icons.error)
],)
, backgroundColor: Colors.red,)
);
}
child:
// 可以接著使用BlocBuilder或其他widget
BlocListener一樣擁有condition參數可以依照前一個和現在的State決定是否要執行listener內的行為。
BlocListener<LoginBloc, LoginState>(
condition: (previousState, currentState) {
// 回傳true會執行listener
// 回傳false不會執行listener
}
listener: (BuildContext context, LoginState state) {
if (state.isFailure) {
......
}
child:
// 可以接著使用BlocBuilder或其他widget
若有多個Bloc要做監聽一樣有提供MultiBlocListener可以使用。
MultiBlocListener(
listeners: [
BlocListener<BlocA, BlocAState>(
listener: (context, state) {},
),
BlocListener<BlocB, BlocBState>(
listener: (context, state) {},
),
BlocListener<BlocC, BlocCState>(
listener: (context, state) {},
),
],
child: ChildA(),
)
今天的內容比較少,不過介紹的widget都是非常實用的喔。這些widget讓我們不再需要使用setState()
來通知介面需要重建。只要將bloc當作參數,UI不用知道背後的商業邏輯做了什麼事只要監聽到State有變動做出相對應的改變即可,漂亮地將Presentation layer和Business Logic分離。
呼~花了2天介紹Bloc這個套件大家可能有些厭煩了,別擔心明天就回到實作專案的部分,明天再見啦!