[譯]flutter_bloc 最新版本 0.19.0 的最新功能

小德_Kurt發表於2019-08-05

[譯]flutter_bloc 最新版本 0.19.0 的最新功能

flutter_bloc 是實現了 BLoC 模式的第三方庫,可以讓你很方便的使用 BLoC 模式開發 Flutter 應用。

Hi,大家好!我興奮的宣佈 flutter_bloc 釋出了最新的版本 v0.19.0,其中包含了社群要求的幾個特性,最重要的是提升了開發體驗和減少模板程式碼。

在介紹更新的特性之前,我想先感謝社群裡那些反饋使用體驗、建立 PR、和提 isuues 的人,如果沒有你們的共享的話,我們很難實現這些新特性。

廢話不多說,現在讓我們看看更新了哪些新特性!

BlocProvider 的改進

在此之前,為了初始化和回收 bloc,一般都會使用 StatefulWidget 來建立 bloc,因為 StatefulWidget 相比 StatelessWidget 自帶生命週期。但是這也導致了許多模板程式碼,而且也會帶來一些問題,例如很容易忘記釋放 bloc 或者在 build 方法裡初始化 bloc。為了解決這些問題,社群裡有人甚至建立了外掛,如 flutter_bloc_extensions 。我很高興的宣佈,這些的反饋已經被採納了,現在 BlockProvider 已經可以自動的釋放 blocs。

BlockProvider 現在有兩種使用方法。

第一種方法是使用預設的建構函式:

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return BlocProvider(
      builder: (BuildContext context) => MyBloc(),
      child: MyChild(),
    );
  }
}
複製程式碼

在此之前,你只能這麼寫:

class MyWidget extends StatefulWidget {
  State<MyWidget> createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  MyBloc _myBloc;
  
  @override
  void initState() {
    super.initState();
    _myBloc = MyBloc();
  }
  
  @override
  Widget build(BuildContext context) {
    return BlocProvider(
      bloc: _myBloc,
      child: MyChild(),
    );
  }
  
  @override
  void dispose() {
    _myBloc.dispose();
    super.dispose();
  }
}
複製程式碼

你可以看到,在此之前,需要使用 StatefulWidget 來寫 bloc,但現在只需要使用 StatelessWidget 就可以了,實現 bloc 的程式碼量大幅減少,而且會自動釋放 bloc,所以不用擔心 bloc 的釋放問題。

第二種方法是使用 BlocProvidervalue 建構函式:

Navigator.of(context).push(
  MaterialPageRoute<MyPage>(
    builder: (context) {
      return BlocProvider.value(
        value: BlocProvider.of<MyBloc>(context),
        child: MyPage(),
      );
    },
  ),
);
複製程式碼

在上面的例子中,把一個已經存在的 MyBloc 例項給 MyPage 使用,MyPage 是一個新頁面,使用 Navigator 開啟。在這個例子裡,我們要為 MyPage 提供一個已經存在的 MyBloc 例項,並且不希望釋放 MyBlocMyPage 頁面關閉的時候,因為還有其他地方在使用 MyBloc。所以,我們可以使用 BlocProvidervalue 建構函式為 Widget 提供一個已經存在的 bloc 並且不會自動釋放。可以點選 route_access_recipe 檢視更多。

總結一下,如果你要建立一個新的 bloc 給子樹使用,就可以使用 BlocProvider 的預設建構函式來建立 bloc 例項,會有自動釋放 bloc 的功能。但是如果只是要給子樹提供一個已經存在的 bloc 例項,這個時候就不需要自動釋放 bloc 的功能,所以使用 BlocProvidervalue 建構函式。想要釋放 bloc 的話,就在建立 bloc 的地方釋放。

你現在就不需要使用 StatefulWidget 來管理你的 blocs 了。

MultiBlocProvide(之前是 BlocProviderTree)

MultiBlocProvide 的功能是把多個 BlocProvider 合併到一起。

MultiBlocProvide 因為消除了多個 BlocProvider 的巢狀,所以提高了程式碼的可讀性。

在此之前,多個 BlocProvider 是這麼寫的:

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return BlocProvider<BlocA>(
      builder: (BuildContext context) => BlocA(),
      child: BlocProvider<BlocB>(
        builder: (BuildContext context) => BlocB(),
        child: BlocProvider<BlocC>(
          builder: (BuildContext context) => BlocC(),
          child: ChildA(),
        )
      ),
    );
  }
}
複製程式碼

有了 MultiBlocProvide,就可以這麼寫:

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MultiBlocProvider(
      providers: [
        BlocProvider<BlocA>(
          builder: (BuildContext context) => BlocA(),
        ),
        BlocProvider<BlocB>(
          builder: (BuildContext context) => BlocB(),
        ),
        BlocProvider<BlocC>(
          builder: (BuildContext context) => BlocC(),
        ),
      ],
      child: ChildA(),
    );
  }
}
複製程式碼

在上面的例子裡,我們為 ChildA 提供了 BlocA,BlocB,BlocC 三個 bloc。使用 MultiBlocProvider 可以無需額外的巢狀,可以讓我們的程式碼更好讀。

Repository Provider (之前是 ImmutableProvider)

Repository Provider 是新引進來的 provider,專門用於在 widget 樹中處理 repositories, repositories 用於處理資料請求,類似於 Redux 中的 Middleware。想要知道 repository 是什麼和怎麼用的,可以點選這裡檢視。

從架構上看,repository 是一個或多個 data providers 的封裝,並且負責與 bloc 通訊。所以,在整個 Widget 樹裡能訪問 repositories 是非常重要的,隨著最近的更新,這個功能很容易就能實現。

我們可以使用 RepositoryProvider 預設的建構函式建立和提供 repository:

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return RepositoryProvider(
      builder: (context) => MyRepository(),
      child: MyChild(),
    );
  }
}

class MyChild extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return BlocProvider(
      builder: (context) => MyBloc(RepositoryProvider.of<MyRepository>(context)),
      child: MyOtherChild(),
    );
  }
}
複製程式碼

在上面的例子中,我們為 MyChild 及其子樹 建立了 MyRepository 的例項。然後在接下來的 Widget 樹裡建立的 MyBloc (MyBloc 依賴 MyRepository) 可以使用 RepositoryProvider.of 訪問 MyRepository 的例項。你會發現 MyRepository 的 API 和 BlocProvider 非常像,這樣的話就會更加容易使用。

MultiRepositoryProvider (過去是 ImmutableProviderTree)

MultiRepositoryProvider 的功能是把多個 RepositoryProvider 合併到一起。

MultiRepositoryProvider 因為消除了多個 RepositoryProvider 的巢狀,所以提高了程式碼的可讀性。

在此之前,多個 RepositoryProvider 是這麼寫的:

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return RepositoryProvider<RepositoryA>(
      builder: (context) => RepositoryA(),
      child: RepositoryProvider<RepositoryB>(
        builder: (context) => RepositoryB(),
        child: RepositoryProvider<RepositoryC>(
          builder: (context) => RepositoryC(),
          child: ChildA(),
        )
      )
    );
  }
}
複製程式碼

有了 MultiRepositoryProvider,就可以這麼寫:

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MultiRepositoryProvider(
      providers: [
        RepositoryProvider<RepositoryA>(
          builder: (context) => RepositoryA(),
        ),
        RepositoryProvider<RepositoryB>(
          builder: (context) => RepositoryB(),
        ),
        RepositoryProvider<RepositoryC>(
          builder: (context) => RepositoryC(),
        ),
      ],
      child: ChildA(),
    );
  }
}
複製程式碼

在上面的例子裡,我們為 ChildA 提供了 RepositoryA,RepositoryB,RepositoryC 。使用 MultiRepositoryProvider 可以無需額外的巢狀,可以讓我們的程式碼更好讀。

整合 Provider

你可能注意到,新的 BlocProviderRepositoryProvider 的 API 和 Provider 很像。v0.19.0 的最大更新就是底層使用了 Provider,這樣開發者就可以擁有一個具有一致 API 的依賴注入庫。在這裡特別感謝 Remi Rousselet 的反饋和耐心。

flutter_bloc 還會繼續吸收接納其他的 providers(因為 flutter_bloc 會接受社群裡的其他反饋),但是我們非常激動在底層使用 Provider,這樣的話我們就不需要使用之前 我們自己的 InheritedWidget 的封裝,不需要自己來維護,而是直接享受到 Provider 未來更新帶來的新特性。

你可以檢視我們完整的 change_log 來檢視更多的資訊。

相關文章