freezed的作用
用于自动生成不可变数据类和联合类型(sealed unions)的代码生成库。
引入
sql
flutter pub add freezed_annotation
flutter pub add --dev build_runner
flutter pub add --dev freezed
# 如果需要 JSON 序列化
flutter pub add json_annotation
flutter pub add --dev json_serializable
引入build_runner后可以通过执行
dart run build_runner build --delete-conflicting-outputs自动注解
如果遇到 invalid_annotation_target 警告,可以在 analysis_options.yaml 加:
makefile
analyzer:
errors:
invalid_annotation_target: ignore
应用场景
-
DTO / Model 写法
比如用户接口返回:
json{ "id": "u001", "nickname": "Tom", "avatar_url": "https://xxx.com/a.png", "tags": ["vip", "new"] }推荐这样写:
dartimport 'package:freezed_annotation/freezed_annotation.dart'; part 'user_dto.freezed.dart'; part 'user_dto.g.dart'; @freezed abstract class UserDto with _$UserDto { const factory UserDto({ required String id, @Default('') String nickname, @JsonKey(name: 'avatar_url') String? avatarUrl, @Default(<String>[]) List<String> tags, }) = _UserDto; factory UserDto.fromJson(Map<String, Object?> json) => _$UserDtoFromJson(json); }使用:
inifinal user = UserDto.fromJson(json); final updated = user.copyWith( nickname: 'Jerry', );Freezed 会自动生成不可变字段、
copyWith、toString、==、hashCode;如果定义了fromJson,还会配合json_serializable生成序列化逻辑。 -
页面状态初始化写法
-
例如类似搜索页这种有个初始页面状态的,可以这样管理
dart///页面状态有这几样的,推荐这样管理 ///initial:还没开始请求,或者等待用户输入 ///loading:正在加载 ///success:加载成功,有数据 ///failure:加载失败 ///empty:加载成功,但无数据 ///用户详情页 ///订单详情页 ///房间详情页 ///商品详情页 ///搜索结果页 ///消息列表页 ///基金持仓页 @freezed sealed class UserPageState with _$UserPageState { const factory UserPageState.initial() = UserPageInitial; const factory UserPageState.loading() = UserPageLoading; const factory UserPageState.empty() = UserPageEmpty; const factory UserPageState.success({ required List<UserDto> users, @Default(false) bool isRefreshing, @Default(false) bool isLoadingMore, @Default(false) bool hasMore, }) = UserPageSuccess; const factory UserPageState.failure({ required String message, }) = UserPageFailure; } -
类似用户详情页状态,则直接用
AsyncValue表示即可scss/// provider final userDetailProvider = FutureProvider.family<UserDto, String>((ref, userId) async { final repository = ref.watch(userRepositoryProvider); return repository.fetchUserDetail(userId); }); /// 页面 Widget build(BuildContext context, WidgetRef ref) { final userAsync = ref.watch(userDetailProvider(userId)); return switch (userAsync) { AsyncLoading() => const Center( child: CircularProgressIndicator(), ), AsyncError(:final error) => ErrorView( message: error.toString(), ), AsyncData(:final value) => UserDetailView( user: value, ), _ => const SizedBox.shrink(), }; }
- 默认值
less
///不写nullable,写默认值
@Default('') String title
@Default(0) int count
@Default(false) bool selected
@Default(<ItemDto>[]) List<ItemDto> items
- 嵌套json时需要用
@JsonSerializable(explicitToJson: true)
scala
@freezed
abstract class RoomDto with _$RoomDto {
@JsonSerializable(explicitToJson: true)
const factory RoomDto({
required String id,
required UserDto owner,
@Default(<UserDto>[]) List<UserDto> members,
}) = _RoomDto;
factory RoomDto.fromJson(Map<String, Object?> json) =>
_$RoomDtoFromJson(json);
}