[Flutter] copyWith로 Nullable 변수 사용해 보기

Tyger·2023년 12월 15일
1

Flutter

목록 보기
49/64
post-custom-banner

copyWith로 Nullable 변수 사용해 보기

[NEW] copyWith에 NULL 사용하는 방법

이번 시간에는 copyWith 사용시 Nullable 타입의 변수를 사용하는 방법에 대해서 살펴보려고 한다.

copyWith는 class 복사 기능으로 객체의 변수를 변경하는데 사용된다. 하지만 copyWith 선언을 보면 Null 타입을 받을 수 없게 되어있고, 실제로도 Null 값을 주어도 값이 변하지 않는다는 것을 알 수 있다.

먼저 테스트를 위해 Person 객체를 하나 만들어 보자.

여기서 age, city 변수는 Nullable 타입으로 선언하였다.

class Person {
  final int id;
  final String name;
  final int? age;
  final String? city;
  
  const Person({
    required this.id,
    required this.name,
	this.age,
	this.city,
  });
}

로그 출력을 위해 Person 객체의 toString() 함수를 재정의 해주자.


toString() => "id : $id, name : $name : age : $age, city : $city";

tyger라는 Person 객체를 아래와 같이 생성해서 출력해보자. 정상적으로 출력이 된다.

void main() {
  Person tyger = const Person(id: 1, name : "Tyger", age : 20, city : "Seoul");
  print(tyger.toString());
}

// id : 1, name : Tyger : age : 20, city : Seoul

이번에는 copyWith를 추가해주도록 하자. 혹시라도 copyWith 기능에 대해서 잘 모르시는 분들은 아래 댓글 남겨주시면 copyWith에 대한 글도 따로 작성해서 공유하도록 하겠습니다.

  Person copyWith({
    final int? id,
    final String? name,
    final int? age,
    final String? city,
  }){
    return Person(
      id : id ?? this.id,
      name : name ?? this.name,
      age : age ?? this.age,
      city : city ?? this.city,
    );
  }

이제 copyWith를 사용해서 tyger 변수의 id 값을 2로 변경해 주도록 하자. 잘 실행이 된다.

void main() {
  Person tyger = const Person(id: 1, name: "Tyger", age: 20, city: "Seoul");
  print(tyger.toString());
  tyger = tyger.copyWith(id: 2);
  print(tyger.toString());
// id : 1, name : Tyger : age : 20, city : Seoul
// id : 2, name : Tyger : age : 20, city : Seoul
}

그럼 이번엔 age의 값을 30으로 변경해 보도록 하자.

void main() {
  Person tyger = const Person(id: 1, name: "Tyger", age: 20, city: "Seoul");
  print(tyger.toString());
  tyger = tyger.copyWith(age : 30);
  print(tyger.toString());
}

// id : 1, name : Tyger : age : 20, city : Seoul
// id : 1, name : Tyger : age : 30, city : Seoul

이번에는 id, age 값을 각각 3, 40으로 변경해 보겠다. 문제 없이 잘 출력이 되고 있다.

void main() {
  Person tyger = const Person(id: 1, name: "Tyger", age: 20, city: "Seoul");
  print(tyger.toString());
  tyger = tyger.copyWith(id : 3, age : 40);
  print(tyger.toString());
}

// id : 1, name : Tyger : age : 20, city : Seoul
// id : 3, name : Tyger : age : 40, city : Seoul

지금까지는 별다른 문제가 없는데.. 이제부터가 문제다.

city 값을 null로 변경해 보자. city 값이 null로 변경되지 않고 여전히 "Seoul"로 되어있다.

왜 변하지 않는 걸까?

void main() {
  Person tyger = const Person(id: 1, name: "Tyger", age: 20, city: "Seoul");
  print(tyger.toString());
  tyger = tyger.copyWith(city : null);
  print(tyger.toString());
}

// id : 1, name : Tyger : age : 20, city : Seoul
// id : 1, name : Tyger : age : 20, city : Seoul

copyWith를 직접 생성해서 사용하시는 분들은 이런 상황을 경험해 보셨을 거다. 이러한 현상은 copyWith 기능을 만드는 부분에서 파악할 수 있다.

해당 부분을 보면 city 값이 없을 때에 this.city 값을 넣도록 되어 있기에, 우리는 객체를 수정할 때 원하는 값만 넣어서 수정해줄 수 있었던 것이다.

city: city ?? this.city,

그렇다면 Nullable 타입을 사용할 수 없는 걸까 ? 아니다. 사용할 수 있다. 다만 코드를 수정해 주어야 한다.

Nullable 타입을 사용하는 방법은 크게 2가지 정도가 있고, 그 외에도 개발자 각자의 스타일대로 객체를 생성해서 할 수도 있기 때문에 보편적으로 사용하는 2가지 방법만 살펴보도록 하겠다.

첫 번째 방법은 타입을 함수형으로 전달 하게끔 변경하는 방법이다. 방법부터 살펴보도록 하자.

기존 copyWith의 city 변수 부분만 수정해보자. city 변수를 함수 형태로 전달받게 되면 함수가 null을 리턴하게 null 값을 전달할 수 있게 된다.

  Person copyWith({
    final int? id,
    final String? name,
    final int? age,
    final String? Function()? city,
  }) {
    return Person(
      id: id ?? this.id,
      name: name ?? this.name,
      age: age ?? this.age,
      city: city != null ? city() : this.city,
    );
  }

실제 사용할 때는 아래와 같이 사용해야 하는데, 이 부분이 단점이다 ㅠㅠ 함수 형태로 값을 전달해줘야 한다.

void main() {
  Person tyger =
      const Person(id: 1, name: "Tyger", age: 20, city: "Seoul");
  print(tyger.toString());
  tyger = tyger.copyWith(id:3, city: ()=>null);
  print(tyger.toString());
}

// id : 1, name : Tyger : age : 20, city : Seoul
// id : 3, name : Tyger : age : 20, city : null

제가 가장 자주 사용하는 방법인데, 단순히 변수 하나를 추가해 주는 것이다.

nullCity라는 불리언 변수를 사용하는 방법인데, 사용할 때도 함수 형태보다 간단해서 주로 사용하고 있다.

  Person copyWith({
    final int? id,
    final String? name,
    final int? age,
    final String? city,
    final bool nullCity = false,
  }) {
    return Person(
      id: id ?? this.id,
      name: name ?? this.name,
      age: age ?? this.age,
      city: nullCity ? null : city ?? this.city,
    );
  }

city에 null 값을 주고 싶을 때는, "city : null"로 사용하지 않고 "nullCity : true" 라고만 값을 넣어줘도 null 값으로 변경시킬 수 있다.

void main() {
  Person tyger = const Person(id: 1, name: "Tyger", age: 20, city: "Seoul");
  print(tyger.toString());
  tyger = tyger.copyWith(id: 2);
  print(tyger.toString());
  tyger = tyger.copyWith(id: 3, nullCity : true);
  print(tyger.toString());
}

// id : 1, name : Tyger : age : 20, city : Seoul
// id : 2, name : Tyger : age : 20, city : Seoul
// id : 3, name : Tyger : age : 20, city : null

이 외에도 다양한 방법들이 있으며, 객체를 자유롭게 생성하여 사용할 수 있다. 이런 부분이 불필요하고 코드 작성이 너무 많다면, freezed와 같은 코드 제너레이터를 사용하면 간단하게 copyWith를 사용할 수 있다.

profile
Flutter Developer
post-custom-banner

0개의 댓글