불변성(Immutability)이란?
불변성(Immutability)은 Object
의 모든 필드가 final
또는 late final
인 경우입니다. 객체 생성할 때 정확히 한 번만 설정됩니다.
불변성은 여러 가지 이유로 바람직합니다.
- 참조 평등(reference equality)보다 가치 평등(value equality)
- 코드 조각에 대한 로컬 추론
- 멀리 떨어진 코드 조각은 참조(reference)를 통해 바로 아래에서 객체를 변경할 수 없습니다.
- 비동기 및 병렬 작업에 대한 추론이 더 쉬워집니다.
- 다른 코드는 작업 중간에 객체를 변경할 수 없습니다.
- API의 안전성
- 메서드에 전달하는 내용은 호출자/수신자가 변경할 수 없습니다.
copyWith
메서드는 몇 가지만 변경하여 새로운 객체를 만들 때 장황한 내용을 줄이는 데 도움이 됩니다.
다트는 변경되지 않은 하위 객체에 대한 모든 참조를 재사용 할 수 있기 때문에 복사(copy)가 생각보다 효율적입니다.
[!danger] 경고
객체가 완전한 불변인지 확인하세요. 그렇지 않으면 일종의 깊은 복사 메커니즘을 구현해야 합니다.
모범 사례
불변 상태를 생성하는 패키지는 무엇이든 사용할 수 있습니다.
불변 객체의 경우:
불변 컬렉션의 경우(Map
, Set
, List
):
freezed을 사용하는 것을 적극 권장합니다. freezed에는 단순히 불변 객체를 만드는 것 외에도 다음과 같은 몇 가지 멋진 추가 기능이 있기 때문입니다.
- 미리 생성된
copyWith
메소드 - 깊은(deep) 복사(중첩되고 고정된 객체에 대한
copyWith
) - 유니온 타입
- 유니온 매핑 함수
불변 상태로 작업하기 위해 코드 생성을 사용할 필요는 없지만 훨씬 더 쉽게 작업 할 수 있습니다.
[!danger] 경고
기본 제공 컬렉션을 사용하려면 컬렉션을 업데이트할 때 컬렉션 복사본을 만드는 규칙을 적용해야 합니다. 컬렉션을 복사하지 않을 때의 문제점은 Riverpod가 객체에 대한 참조가 변경되었는지 여부에 따라 새 상태를 내보낼지 여부를 결정한다는 것입니다. 객체를 변경하는 메서드만 호출하기만 하면 참조는 동일합니다.
불변 상태 사용하기
불변 상태는 StateNotifier를 StateNotifierProvider와 함께 사용하는데 가장 적합합니다. StateNotifier를 사용하면 상태를 ‘변경’ 할 수 있는 인터페이스를 노출할 수 있습니다. StateNotifier를 확장하는 정의한 클래스 외부에서 상태를 변경할 수 없습니다 . 이를 통해 관심사를 분리하고 비즈니스 로직을 UI 외부에 유지합니다.
다음은 앱 테마를 변경하기 위한 간단한 불변 설정 클래스의 예입니다.
final themeProvider = StateNotifierProvider((ref) => ThemeNotifier());
class ThemeNotifier extends StateNotifier<ThemeSettings> {
ThemeNotifier(): super(
ThemeSettings(
mode: ThemeMode.system,
primaryColor: Colors.blue,
));
void toggle() {
state = state.copyWith(mode: state.mode.toggle);
}
void setDarkTheme() {
state = state.copyWith(mode: ThemeMode.dark);
}
void setLightTheme() {
state = state.copyWith(mode: ThemeMode.light);
}
void setSystemTheme() {
state = state.copyWith(mode: ThemeMode.system);
}
void setPrimaryColor(Color color) {
state = state.copyWith(primaryColor: color);
}
}
@freezed
class ThemeSettings with _$ThemeSettings {
const factory ThemeSettings({ThemeMode mode, Color primaryColor}) = _ThemeSettings;
}
extension ToggleTheme on ThemeMode {
ThemeMode get toggle {
switch (this){
case ThemeMode.dark:
return ThemeMode.light;
case ThemeMode.light:
return ThemeMode.dark;
case ThemeMode.system:
return ThemeMode.system;
}
}
}
이 코드를 사용하려면 freezed_annotation
을 임포트한 후 part
지시문을 추가하고, build_runner를 실행하여 freezed 클래스를 생성하세요.
or
'개발 > 플러터(Flutter)' 카테고리의 다른 글
(Flutter) 플러터에서 Openai API 사용하기 (0) | 2023.04.13 |
---|---|
(Flutter) Riverpod의 Provider 종류 (0) | 2023.03.30 |
(Flutter) Riverpod의 Provider Lifecycles (0) | 2023.03.29 |
(Flutter) Riverpod의 ProviderObserver (0) | 2023.03.29 |
(Flutter) Riverpod의 Modifiers (0) | 2023.03.28 |