freezed에서 getter나 void 함수를 그냥 쓰려고하면 오류가 걸린다. 그래서 아래처럼 사용하면 된다.
// 생략
const Person._();
// 밑의 get과 hello를 쓰기 위해 이친구를 사용함 / 그리고 코드에 오류가 발생하기에 다시 build를 해줘야함
// define a private empty constructor:
get nameLength => this.name.length;
void hello() {
print("123");
}
다른 클래스로 묶어서 사용하기..
class Group with _$Group {
factory Group({
required int id,
required String name,
required School school,
}) = _Group;
}
class School with _$School {
factory School({
required int id,
required String name,
}) = _School;
}
그리고 만약 무효하여 쓰고 싶다면 null을 이용한다.
Company company = Company(name: 'Google', director: Director(assistant: null));
기본값 (다트는 factory 생성자 리디렉션이 기본값을 허용하는 것을 원치 않음!
방법은 예제처럼 하기
class Example with _$Example {
const factory Example([(42) int value]) = _Example;
//@default 사용
}
// 직렬화/역직렬화를 사용하는 경우 자동으로 추가됩니다 @JsonKey(defaultValue: <something>).
사용하지 않을려는 것은 @deprecated을 선언하여 수행
class Person with _$Person {
const factory Person({
String? name,
int? age,
Gender? gender,
}) = _Person;
}
union (공통으로 쓰이는 것들을 공유해서 공통이 아닌 것은 기능 잃음)
class Person with _$Person {
//(2)
factory Person({
required int id,
required String name,
required int age,
int? statusCode,
}) = _Person;
// factory Person.data(int value) = _Data // 데이터
factory Person.loading({int? statusCode}) = _Loading; // 로딩
factory Person.error(String message, {int? statusCode}) = _Error; // 에러
}
union.when (패턴 일치를 소멸시키는 기능함 = 공식문서 참고)
mapWhen(Person person) {
return person.when(
(id, name, age, statusCode) =>
'id: $id, name: $name, age: $age, statusCode: $statusCode',
loading: (int? statusCode) => 'loading...',
error: (String message, int? statusCode) => message);
}
renderText('person', person.toString()),
renderText('personLoading', personLoading.toString()),
renderText('personError', personError.toString()),
renderText('personcode', person.statusCode.toString()),
// renderText('person', person.id), 맨 위 객체에선 statusCode만 공통되기에 에러 발생
renderText('person.when', mapWhen(person)),
renderText('personLoading.when', mapWhen(personLoading)),
renderText('personError.when', mapWhen(personError)),
공식문서 예시
class Model with _$Model {
factory Model.first(String a) = First;
factory Model.second(int b, bool c) = Second;
}
var model = Model.first('42');
print(
model.when(
first: (String a) => 'first $a',
second: (int b, bool c) => 'second $b $c'
),
); // first 42
Map (when 과 비슷.. 구조화는 시키지 않음
var model = Model.first('42');
print(
model.map(
first: (First value) => 'first ${value.a}',
second: (Second value) => 'second ${value.b} ${value.c}'
),
); // first 42
var model = Model.second(42, false)
print(
model.map(
first: (value) => value,
second: (value) => value.copyWith(c: true),
)
); // Model.second(b: 42, c: true)
is / as를 사용하여 Freezed class read
void main() {
Example value;
if (value is Person) {
// By using `is`, this allows the compiler to know that "value" is a Person instance
// and therefore allows us to read all of its properties.
print(value.age);
value = value.copyWith(age: 42);
}
// Alternatively we can use `as` if we are certain of type of an object:
Person person = value as Person;
print(person.age);
}
implements / @with 이용한 공용 유형 개별클래스mixin / interface
// 동일한 클래스에 여러 유형이 있는 경우 하나를 만들어 인터페이스 구현 /클래스 혼합 가능
abstract class GeographicArea {
int get population;
String get name;
}
class Example with _$Example {
const factory Example.person(String name, int age) = Person;
<GeographicArea>()
const factory Example.city(String name, int population) = City;
}
제네릭 믹스인 또는 인터페이스를 지정하려는 경우
With.fromString생성자 를 사용하여 Implements.fromString각각 문자열로 선언
// 모든 추상 멤버를 구현하여 인터페이스 요구 사항을 준수하는지 확인
// 고정 클래스 에는 @With/ 를 사용할 수 없습니다 . @Implements고정 클래스는 확장하거나 구현할 수 없습니다.
abstract class GeographicArea {}
abstract class House {}
abstract class Shop {}
abstract class AdministrativeArea<T> {}
class Example with _$Example {
const factory Example.person(String name, int age) = Person;
<AdministrativeArea<House>>()
const factory Example.street(String name) = Street;
<House>()
<Shop>()
<GeographicArea>()
const factory Example.city(String name, int population) = City;
}
FromJson /ToJson
jsonserializable 패키지를 이용해서 만듬.
1.part '{name}.g.dart'; 을 선언
2. factory {name}.fromJson(Map<String, dynamic> json) => ${name}FromJson(json); 선언
Freezed는 팩토리에서 를 사용하는 경우에만 fromJson을 생성
만약 여러 생성자가 있는 클래스에서 fromJson을 사용한다면. runtimeType을 이용해서 사용할 생성자 선택(공식문서 참조)
class MyResponse with _$MyResponse {
const factory MyResponse(String a) = MyResponseData;
const factory MyResponse.special(String a, int b) = MyResponseSpecial;
const factory MyResponse.error(String message) = MyResponseError;
factory MyResponse.fromJson(Map<String, dynamic> json) => _$MyResponseFromJson(json);
}
[
{
"runtimeType": "default",
"a": "This JSON object will use constructor MyResponse()"
},
{
"runtimeType": "special",
"a": "This JSON object will use constructor MyResponse.special()",
"b": 42
},
{
"runtimeType": "error",
"message": "This JSON object will use constructor MyResponse.error()"
}
]
(unionKey: 'type', unionValueCase: FreezedUnionCase.pascal)
class MyResponse with _$MyResponse {
const factory MyResponse(String a) = MyResponseData;
('SpecialCase')
const factory MyResponse.special(String a, int b) = MyResponseSpecial;
const factory MyResponse.error(String message) = MyResponseError;
// ...
}
[
{
"type": "Default",
"a": "This JSON object will use constructor MyResponse()"
},
{
"type": "SpecialCase",
"a": "This JSON object will use constructor MyResponse.special()",
"b": 42
},
{
"type": "Error",
"message": "This JSON object will use constructor MyResponse.error()"
}
]
다른 yaml 파일을 만들어서 선언할수도 있음!
JSON 응답을 제어하지 않는 경우 사용자 지정변환기 구현 가능(사용자 지정 변환기는 사용할 생성자를 결정하기 위한 자체 논리를 구현)
class MyResponseConverter implements JsonConverter<MyResponse, Map<String, dynamic>> {
const MyResponseConverter();
MyResponse fromJson(Map<String, dynamic> json) {
// type data was already set (e.g. because we serialized it ourselves)
if (json['runtimeType'] != null) {
return MyResponse.fromJson(json);
}
// you need to find some condition to know which type it is. e.g. check the presence of some field in the json
if (isTypeData) {
return MyResponseData.fromJson(json);
} else if (isTypeSpecial) {
return MyResponseSpecial.fromJson(json);
} else if (isTypeError) {
return MyResponseError.fromJson(json);
} else {
throw Exception('Could not determine the constructor for mapping from JSON');
}
}
Map<String, dynamic> toJson(MyResponse data) => data.toJson();
}
class MyModel with _$MyModel {
const factory MyModel(() MyResponse myResponse) = MyModelData;
factory MyModel.fromJson(Map<String, dynamic> json) => _$MyModelFromJson(json);
}
class MyModel with _$MyModel {
const factory MyModel(() List<MyResponse> myResponse) = MyModelData;
factory MyModel.fromJson(Map<String, dynamic> json) => _$MyModelFromJson(json);
}
freezed 다양한 매개변수 출력 변경
(
// Disable the generation of copyWith/==
copyWith: false,
equal: false,
)
class Person with _$Person {...}