👏

Flutter freezed のチートシート、もとい、知っている人向けのメモ

2021/07/27に公開

分かっている人(というか自分)向けのメモです。LiveTemplateなども記載した詳細な記事も作成しましたので、初めての方はそちらをご覧下さい。

インストール

ターミナルで実行する。ただし、5行をまとめて実行できない。1行ずつ実行する。

flutter pub add freezed_annotation
flutter pub add build_runner --dev
flutter pub add freezed --dev
flutter pub add json_serializable --dev
flutter pub add json_annotation

作成するクラス

ソーステンプレート

templateとTemplateを、自分の作成するクラスに合わせて修正する。

import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:flutter/foundation.dart';

part 'template.freezed.dart';
part 'template.g.dart';

@freezed
class Template with _$Template {
  const factory Template({
    required String title,
  }) = _Template;

  factory Template.fromJson(Map<String, dynamic> json) =>
      _$TemplateFromJson(json);
}

実例と解説

@freezed
class Template with _$Template {
  @Assert('(questions == null) != (asinQuestions == null)',
      'questionsとasinQuestionsはどちらかは設定する必要がある')
  const factory Template({
    // requiedか?をつける
    required String title,
    String? comment,

    // デフォルト値の設定
    @Default(0) int questionLength,
    
    // ListもMapも読み込める。素晴らしい!
    List<String>? questions,
    List<String>? asinQuestions,
    
    // オブジェクトもJson読込が定義されていれば、入れられる
    required Map<String, ResultInfoData> resultInfo,
  }) = _WorkbookData;
}

Assert

作成されたデータの条件を定義できる。
第一引数の式が展開される。ただの文字列のため、build時にエラーが発生する。
(questions == null) != (asinQuestions == null)
というのは、questionsとasinQuestiosがnullか確認している。二つの回答が異なる場合、trueとfaluseだった場合、「!=」が成立する。つまり、片方が入力されているときのみ有効になる。両方値が入ったり、両方nullだった場合はエラーになる。

コード生成

・通常のコード生成

flutter pub run build_runner build

・コードの生成(強制)

flutter pub run build_runner build --delete-conflicting-outputs

・変更を監視してコード生成(ファイルを保存したら、自動でbuildされる)

flutter pub run build_runner watch

Jsonの読み書き

リストでないJsonの読込

var file = File('assets/data.json');
WorkboodData workboodData =
	WorkbookData.fromJson(json.decode(file.readAsStringSync()));

リストのJsonの読込

var file = File('assets/list.json');
List<dynamic> jsonData = json.decode(file.readAsStringSync());
List<OverviewData> overviewData =
	jsonData.map((data) => OverviewData.fromJson(data)).toList();

以下のようにまとめて書いたら、エラーになった。

json.decode(file.readAsStringSync()).map((data) => OverviewData.fromJson(data)).toList();

Jsonの書込

var output = File('test/result/test.json');
output.writeAsStringSync(json.encode(copy));

注意点

メンバー変数のうち、
intやString、freezedで生成したクラスは変更できないが、
ListとMapは変更できる。

// List
expect(copy.asinQuestions!.length, 95);
copy.asinQuestions!.removeLast();
expect(copy.asinQuestions!.length, 94);

// Map
expect(copy.resultInfo!.length, 4);
expect(copy.resultInfo.remove('rankA'), isNotNull);
expect(copy.resultInfo!.length, 3);

json_serializerとの比較

freezedの方が良いと考える

良い点

classの中で変数名を1回しか書かなくて良い
→json_serializerの場合、変数の定義とコンストラクタの定義で2回書く

悪い点

json変換を書いたとき、ファイルが2つ生成され、クラスファイルが3つになる
→son_serializerの場合、ファイルが1つ生成され、クラスファイルが2つ

単にテストを作りながら作ったから、快適だっただけかも、、

やらかしたエラーの履歴

type 'Null' is not a subtype of type 'Map<String, dynamic>' in type cast

fromJson実施時に、クラスの変数名とjsonの要素名が異なっていた。

You are missing a required dependency on json_annotation in the "dependencies" section of your pubspec with a lower bound of at least "4.3.0".

flutter pub add json_annotation
を実施したら解決した。以前はjson_annotationのプラグインがなくても実施できたけど、なんか変わったかな。

より詳しく学習するために

freezedはよくriverpodと一緒に使われます。riverpodも学習したい!という場合は、以下のUdemy講座をご利用ください。riverpodの基本から、MVVMモデルへの応用、もちろん、WebAPIやFirestoreからのデータも取り扱っています。ぜひご受講ください。
クーポンコードもありますので、ご利用ください。

Flutter x Riverpod x MVVMで実現するシンプルな設計

https://zenn.dev/sakusin/articles/a00aa8af321f54

Discussion