flutter freeze (2)

Sunny·2022년 6월 6일

Freezed

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 {...}
profile
즐거움을 만드는 사람

0개의 댓글