Flutterのfreezedパッケージを調べたときの備忘録。
freezedとは
Dartでデータクラスのような機能を提供するパッケージ。
- コンストラクタだけのシンプルなモデル定義
- オブジェクトをクローンできる
copyWith
メソッド - union-types/pattern matching
- 自動的なserialization/deserialization
- すべてのプロパティを比較/表示する
==
/toString
@freezed
などのアノテーションを付けたクラス(モデル定義)に対し、
build_runner
を使ったコード生成によって、
これらの便利な機能を提供してくれる。
インストール
3つのパッケージをインストールする。
# pubspec.yaml dependencies: freezed_annotation: dev_dependencies: build_runner: freezed:
$ flutter pub add freezed_annotation $ flutter pub add -d freezed $ flutter pub add -d build_runner $ flutter pub get
.freezed.dart
などで、警告が出ないようにするために、
analysis_options.yaml
に設定を追加。
# analysis_options.yaml analyzer: exclude: - "**/*.g.dart" - "**/*.freezed.dart" errors: invalid_annotation_target: ignore
モテルを定義する
モデルは@freezed
などを使って定義する。
お作法的な部分が多いけど、こんな感じ。
// ./User.dart import 'package:freezed_annotation/freezed_annotation.dart'; // 自動生成したコードを取り込む part 'User.freezed.dart'; // モデル定義 @freezed class User with _$User { const factory User({required String name}) = _User; }
定義しただけだと、コード生成前なのでコンパイルエラーになる。
コード生成のために、以下のコマンドを実行する。
$ flutter pub run build_runner build
コマンドを実行すると、_$User
や_User
を含む、
User.freezed.dart
が同じ場所に生成される。
生成が完了すると、こんな感じで使えるようになる。
イミュータブルなクラスなので、再代入はできない。
import './User.dart'; const user = User(name: "user-A");
モデルに独自のメソッドを追加する
自動生成される_$User
はmixinなので、拡張ができず、
そのままだと、メソッドを追加できない。。
独自のメソッドを利用できるよう、
単一のプライベートコンストラクタを追記する必要がある。
// ./User.dart import 'package:freezed_annotation/freezed_annotation.dart'; part 'User.freezed.dart'; // モデル定義 @freezed class User with _$User { const User._(); // メソッドを追加するので、コンストラクタを追加 const factory User({required String name}) = _User; // 独自のメソッド void print() { debugPrint(toString()); } }
モデルにfromJson/toJsonを追加する
json_serializableを使った、
fromJson
/toJson
も簡単に追加できる。
まずは、json_serializable
パッケージを追加。
$ flutter pub add -d json_serializable $ flutter pub get
次に
// ./User.dart import 'package:freezed_annotation/freezed_annotation.dart'; part 'User.freezed.dart'; // JSON用の生成コード part 'User.g.dart'; // モデル定義 @freezed class User with _$User { const factory User({required String name}) = _User; factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json); }
json_serializable
もコード生成して使うので、コマンド実行。
$ flutter pub run build_runner build
すると、User.g.dart
が生成されるので、
こんな感じで使えるように。
// json.decode()/encode()に必要 import 'dart:convert'; import './User.dart'; final user = User.fromJson(json.decode('{"name":"user-A"}')); debugPrint(json.encode(user.toJson()));
文字列を変換する処理もまとめたい場合はこんな感じにもできる。
// ./User.dart import 'dart:convert'; import 'package:freezed_annotation/freezed_annotation.dart'; part 'User.freezed.dart'; part 'User.g.dart'; // モデル定義 @freezed class User with _$User { const User._(); // メソッドを追加するので、コンストラクタを追加 const factory User({required String name}) = _User; factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json); // クラスメソッドに、fromJsonStrメソッドを追加 factory User.fromJsonStr(String jsonStr) => _$UserFromJson(json.decode(jsonStr)); String toJsonStr() { return json.encode(toJson()); } }
import 'dart:convert'; import './User.dart'; final user = User.fromJsonStr('{"name":"user-A"}'); debugPrint(user.toJsonStr());
以上!! 便利(´ω`)