我正在将 Flutter Bloc 与事件和状态一起使用。 我尝试了多种方法,但 copyWith 函数根本不起作用。 该集团每次都会产生现在状态并重置前一个状态。 如何保留以前的状态..?
我的代码是这样的: 我创建了一个包含多个可以触发的事件的块。
class AddressBloc2 extends Bloc<AddressEvent, AddressState> {
AddressBloc2() : super(AddressInitial()) {
on<GetAddressList>(_getAddressList);
on<GetCurrentLocation>(_getCurrentLocation);
on<GetGeoAddress>(_getGeoAddress);
on<AddAddress>(_addAddress);
on<UpdateAddress>(_updateAddress);
on<RemoveAddress>(_removeAddress);
on<SetDefaultAddress>(_setDefaultAddress);
}
void _getAddressList(GetAddressList event, emit) async {
try {
final response = await AddressServices.getAddressList();
final Address? defaultAddress = response
.firstWhereOrNull((element) => element.addressDefault == true);
emit(AddressLoaded(addresses: response, defaultAddress: defaultAddress));
} catch (e) {
emit(AddressError(e.toString()));
}
}
void _getCurrentLocation(GetCurrentLocation event, emit) async {
if (event.currentLocation == null) {
logger('this is crashing currentlocation');
}
emit(
const AddressLoaded().copyWith(currentLocation: event.currentLocation),
);
logger(state);
}
void _getGeoAddress(GetGeoAddress event, emit) async {
if (state is GetGeoAddressLoading) return;
emit(GetGeoAddressLoading());
try {
Map<String, dynamic> geoAddress =
await AddressServices.getGeoAddress(event.currentLocation);
logger('before geoAddress');
logger(state);
emit(const AddressLoaded().copyWith(geoAddress: geoAddress));
logger(state);
} catch (e) {
emit(GetGeoAddressError(e.toString()));
logger(e.toString());
emit(const AddressLoaded());
}
}
}
我的活动文件:
part of 'address_bloc.dart';
sealed class AddressEvent extends Equatable {
const AddressEvent();
@override
List<Object> get props => [];
}
class GetAddressList extends AddressEvent {}
class GetCurrentLocation extends AddressEvent {
final LatLng currentLocation;
const GetCurrentLocation(this.currentLocation);
@override
List<Object> get props => [currentLocation];
}
class GetGeoAddress extends AddressEvent {
final LatLng currentLocation;
const GetGeoAddress(this.currentLocation);
@override
List<Object> get props => [currentLocation];
}
我的状态文件是这样的, 因为我正在获取地址,并从 api 加载地址列表并添加和删除地址。我希望它位于单个块文件中。
part of 'address_bloc.dart';
sealed class AddressState extends Equatable {
const AddressState();
@override
List<Object?> get props => [];
}
class AddressInitial extends AddressState {}
class AddressLoading extends AddressState {}
class AddressLoaded extends AddressState {
final List<Address> addresses;
final Address? defaultAddress;
final LatLng? currentLocation;
final Map<String, dynamic>? geoAddress;
const AddressLoaded({
this.addresses = const [],
this.defaultAddress,
this.currentLocation,
this.geoAddress,
});
@override
List<Object?> get props =>
[addresses, defaultAddress, currentLocation, geoAddress];
AddressLoaded copyWith({
List<Address>? addresses,
Address? defaultAddress,
LatLng? currentLocation,
Map<String, dynamic>? geoAddress,
}) {
return AddressLoaded(
addresses: addresses ?? this.addresses,
defaultAddress: defaultAddress ?? this.defaultAddress,
currentLocation: currentLocation ?? this.currentLocation,
geoAddress: geoAddress ?? this.geoAddress,
);
}
}
class AddressError extends AddressState {
final String error;
const AddressError(this.error);
@override
List<Object> get props => [error];
}
class GetGeoAddressLoading extends AddressState {}
class GetGeoAddressError extends AddressState {
final String error;
const GetGeoAddressError(this.error);
@override
List<Object> get props => [error];
}
除此之外,还有多个事件,它们一起需要更新单个 AddressLoaded 文件。
您应该使用 copyWith 创建一个与原始对象具有相同属性的新对象,但某些值已更改。所以没有任何感觉这样做:
emit(const AddressLoaded().copyWith(geoAddress: geoAddress));
您创建空的新实例,然后使用 copyWith 创建其他新实例。您可以在此answer中查看更多信息。 如果您确定这个案例是真实的,您可以这样做:
void _getCurrentLocation(GetCurrentLocation event, emit) async {
if (event.currentLocation == null) {
logger('this is crashing currentlocation');
}
if (state is AddressLoaded) {
emit(
(state as AddressLoaded).copyWith(currentLocation: event.currentLocation),
);
}
logger(state);
}
但是这里它不适用于复制,因为您在检索数据时声明为 GetGeoAddressLoading 。因此,您可以创建新的 stte,如果您需要一些数据,您可以在将状态更改为加载之前预先提取数据:
void _getGeoAddress(GetGeoAddress event, emit) async {
if (state is GetGeoAddressLoading) return;
final currentLocation = state is AddressLoaded? (state as AddressLoaded).AddressLoaded : null;
//..other data
emit(GetGeoAddressLoading());
try {
Map<String, dynamic> geoAddress =
await AddressServices.getGeoAddress(event.currentLocation);
logger('before geoAddress');
logger(state);
emit(const AddressLoaded(
currentLocation: currentLocation,
//..other data
geoAddress: geoAddress));
logger(state);
} catch (e) {
emit(GetGeoAddressError(e.toString()));
logger(e.toString());
emit(const AddressLoaded());
}
}