[Flutter] copyWith null을 명시적으로적용

박재빈·2025년 3월 13일
0

기본적인 copyWith

class User {
  final String name;
  final int? age;

  User({required this.name, this.age});

  User copyWith({String? name, int? age}) {
    return User(name: name ?? this.name, age: age ?? this.age);
  }
}
void main() {
  User user1 = User(name: 'user1', age: 30);
  print('name : ${user1.name} age : ${user1.age}');
  User user2 = user1.copyWith(name: 'user2', age: null);
  print('name : ${user2.name} age : ${user2.age}');
}

출력 결과

name : user1 age : 30
name : user2 age : 30

특징

  • copyWith는 null을 전달하면 원래 값을 유지하도록 설계
  • age : null을 명시적으로 넣으면 기존 값이 유지된다. -> null을 적용하고 싶을 때 문제가 생김

null을 명시적으로 적용하는 방법

1. bool 을 활용한 방식

구현 방법

class User {
  final String name;
  final int? age;

  User({required this.name, this.age});

  User copyWith({String? name, int? age, bool setAgeNull = false}) {
    return User(
      name: name ?? this.name, 
      age: setAgeNull ? null : (age ?? this.age),
    );
  }
}

출력 결과

void main() {
  User user1 = User(name: 'user1', age: 30);
  print('name : ${user1.name} age : ${user1.age}');
  User user2 = user1.copyWith(name: 'user2', setAgeNull : true);
  print('name : ${user2.name} age : ${user2.age}');
}
name : user1 age : 30
name : user2 age : null

특징

  • copyWith를 통해서 null을 지정할 수 있다.
  • 모든 nullable 변수에 대해 boolean타입의 플래그를 추가하면 코드가 길어지고 관리가 복잡해진다.
    User copyWith({String? name, int? age, bool setAgeNull = false, String? email, bool setEmailNull = false}) {
      return User(
        name: name ?? this.name,
        age: setAgeNull ? null : (age ?? this.age),
        email: setEmailNull ? null : (email ?? this.email),
      );
    }
  • 사용할 때 boolean타입의 파라미터를 추가로 지정해줘야 한다.
    • 일반적인 copyWith는 원하는 값만 전달하면 되는데, null을 지정하려면 추가적인 파라미터를 작성해야함.

2. NullWrapper를 활용하는 방법

nullable 변수를 감싸는 래퍼 클래스를 만들어 null을 명시적으로 적용할 수 있게 하는 방식이다.

구현 방법

class NullWrapper<T> {
  final T? value;
  const NullWrapper(this.value);
}
class User {
  final String name;
  final int? age;

  User({required this.name, this.age});

  User copyWith({String? name, NullWrapper<int>? age}) {
    return User(
      name: name ?? this.name, 
      age: age == null ? this.age : age.value,
    );
  }
}

출력 결과

void main() {
  User user1 = User(name: 'user1', age: 30);
  print('name : ${user1.name} age : ${user1.age}');
  User user2 = user1.copyWith(name: 'user2');
  print('name : ${user2.name} age : ${user2.age}');
  User user3 = user1.copyWith(name: 'user3', age : NullWrapper(null));
  print('name : ${user3.name} age : ${user3.age}');
  User user4 = user1.copyWith(name: 'user4', age : NullWrapper(20));
  print('name : ${user4.name} age : ${user4.age}');
}
name : user1 age : 30
name : user2 age : 30
name : user3 age : null
name : user4 age : 20

특징

  • null을 전달해도 기존 값 유지
  • NullWrapper(null)을 전달하면 명확하게 null을 적용할 수 있다.
  • copyWith를 사용할 때 NullWrapper(value)를 써야 하는 불편함 있음

0개의 댓글