##以前の振り返り
以前の記事でFlutterのUI構築をハンズオン形式で学んでいきました。
具体的には、Flutterとは何か、StatelessWidgt、StatefulWidgetの違い、その他のWidgetなどを学んでいきました。以下のURLから見てください。
Flutterハンズオン(UI構築編)
以前の記事で、とりあえず見た目の部分は完成したので、今回の記事で状態管理の方法を学び、実際にニュースのデータを取ってきて表示していきましょう。
git clone https://github.com/shokiogawa/hands_on.git
にコードのデータがあるので、こちらのコードをベースに進めてください。
##Flutterでの状態管理
今の段階では、statelessWidgetを使っています。しかし、状態を管理するため、stateFulWidgetを使用しないといけないかというと、そうではありません。
もちろん、statefulwidgetを使用した方法もあるのですが、今回は、状態管理にProviderというライブラリを活用します。
このproviderを使うと、statelesswidgetなのかstatefulwidgetなのかを意識することなく状態を管理することが出来ます。
###Providerとは??
Providerとはパッケージの名前で、Flutterの状態管理の一つの手法です。
手法の一つといったようにFlutterには多くの状態管理の方法があります。しかし、そのなかでもGoogleはprovider推奨しています。
詳しくはFlutterの状態管理から見てください。
また、このproviderの中でも、複数の状態管理手法があります。
・Provider
・change_notifier
・state_notifier
etc...
この中で、今回はstate_notifierを使い状態管理をしていきます。
また、state_notifierと同時にfreezedというパッケージも合わせて使用します。
###freezedとは
freezedは、イミュータブルなデータモデルを作成するために使うパケージです。
また、stateにcopyWithというメソッドが自動で作成されます。
state_notifierは管理する状態をイミュータブルなものとして扱うため、freezedと相性が良いです。
言葉で説明されても難しいと思うので実際にコードを書きながら学んでいきましょう。
##state_notifierとfreezedを使った状態管理
Flutterでこれらのパッケージを使い状態管理をする場合、いくつかのステップがあります。
- パッケージをインストール
- freezedでイミュータブルなデータを管理するクラスを作成する。
- 1.で作成したデータクラスをもとにfreezedのパッケージを使い自動でコードを生成する。(ここで、copyWithなどのメソッドが生成される。)
- 1.で作成したデータモデルをもとに、状態を変化させるロジックなどを管理するクラスを作成する。(クラスはstateNotifierを継承)
ここでわかる通り、二つのクラスを作成します。
1つは状態を保管するクラス(freezed)。
もう1つはその状態を変化させるためのクラス(state_notifier)です。
###ステップ1: 必要なパッケージをインストールする
pubspec.yamlに以下のパッケージを記述しインストールします。
dependencies:
flutter:
sdk: flutter
provider: ^4.1.0-dev
state_notifier: ^0.4.0
flutter_state_notifier: ^0.3.0
freezed_annotation:
dev_dependencies:
flutter_test:
sdk: flutter
build_runner:
freezed:
開発日によってそれぞれのバージョンが異なる可能性があるので、一つ一つチェックしてください。
state_notifier
flutter_state_notifier
freezed
freezed_annotation
provider
build_runner
###ステップ2: freezedでイミュータブルなデータを管理するクラスを作成する
part 'news_controller.freezed.dart';
@freezed
abstract class NewsState with _$NewsState {
factory NewsState({
List<Article> articles,
}) = _NewsState;
}
ここでは、ニュースの情報を管理するクラスの名前を、NewsStateとします。
NewsStateクラスの中にあるarticles(型 List )にニュースのデータが入ります。
今の段階では、エラーが出ると思いますが、いまはほっておいて大丈夫です。
###ステップ3: freezedのパッケージを使いコードを自動生成。
コードを自動生成していきます。
ターミナルで、flutter pub run build_runner build
と打つと、自動でコードが生成されます。
news_controller.dartがあるディレクトリにnews_controller.freezed.dartというファイルが自動で作られたと思います。
この段階でステップ2で出ていたエラーが消えたかと思います。
###ステップ4: 状態を変化させるロジックなどを管理するクラスを作成する
今回は、apiからnewのデータを取ってきたいので、newsデータを取ってきて、ステップ1で作成したarticles
に代入するロジックをこのクラスで書きます。
class NewsController extends StateNotifier<NewsState> {
//apiからデータを照ってくる処理が書いてあるクラスのインスタンス化
NewsQueryService _newsQueryService = NewsQueryService();
NewsController() : super(NewsState());
//ニュース情報を、apiからとってきて、NewsStateの中のarticlesに格納するメソッド
Future<void> getNews() async {
List<Article> articles = [];
articles = await _newsQueryService.getNews();
//NewsStateで格納しているデータの変更処理(state変数にすべて格納されている)
//データの変更するためには、copyWithメソッドを使用する。
state = state.copyWith(articles: articles);
}
}
上のコードで書かれている、getNewsメソッドでニュースデータをapiからとってきて、NewsStateクラスの中のarticlesに格納しています。
ちなみに、NewsQueryServiceクラスに関しては、
class NewsQueryService {
final ApiService _apiService = ApiService.create();
Future<List<Article>> getNews() async {
Response response;
List<Article> result = List<Article>();
try {
response = await _apiService.getHeadlines();
if (response.isSuccessful) {
final responseBody = response.body;
result = News.fromJson(responseBody).articles;
} else {
final error = response.error;
print('isSuccessful$error');
}
} catch (error) {}
return result;
}
}
となっており、NewsQueryServiceクラスのgetNewsメソッドはListのArticleを返しています。それを、NewsControllerのメソッドで、NwesState内のarticlesに格納しています。
他にも必要なコードがありますが、こちらで提供します。
これで、apiからのデータをNewsStateのクラスに格納することに成功しました。
次は、実際にそのデータを画面に表示していきます。