简体   繁体   English

Flutter BLoC:如何使用 null 值更新 state?

[英]Flutter BLoC : how to update state with null values?

How do you deal with "accepted null values" when you update a state in BLoC?当您在 BLoC 中更新 state 时,如何处理“接受的 null 值”? I use the flutter_bloc package.我使用flutter_bloc package。

I have a form in which numeric variables are nullable so that I can check their validity before the form is submitted.我有一个表格,其中数字变量可以为空,以便我可以在提交表格之前检查它们的有效性。 But when I emit a new state, I use state.copyWith(var1?, var2?)... so when a null value is used to update a parameter, the value is not updated.但是当我发出一个新的 state 时,我使用 state.copyWith(var1?, var2?)... 所以当 null 值用于更新参数时,该值未更新。

To face that I use a custom FieldStatus enum for each field.面对这一点,我为每个字段使用自定义 FieldStatus 枚举。 In my form submission, I can check the status of each field.在我的表单提交中,我可以检查每个字段的状态。 But this is a bit verbose... and it needs to use 2 values instead of 1 for each field, which is not very satisfying.但这有点冗长......并且它需要为每个字段使用 2 个值而不是 1,这不是很令人满意。

I can also force the value to be null according to the new value of its FieldStatus, but it is a bit tricky and not very satisfying.我也可以根据它的FieldStatus的新值强制取值为null,但是有点棘手,不是很满意。

How would you manage such a case?你会如何处理这样的案件?

Here is what I did:这是我所做的:

States:状态:

part of 'phhfgroup_bloc.dart';

class PhhfGroupState extends Equatable
{
    final double? height;
    final FieldStatus heightStatus;
    
    const PhhfGroupState({this.height, this.heightStatus = FieldStatus.initial});
    
    @override
    List<Object?> get props => [height, heightStatus];
    
    PhhfGroupState copyWith({double? height, FieldStatus? heightStatus})
    {
        return PhhfGroupState(
            height: height ?? this.height,
            heightStatus: heightStatus ?? this.heightStatus
        );
    }
}

Events:事件:

part of 'phhfgroup_bloc.dart';

abstract class PhhfGroupEvent extends Equatable
{
    const PhhfGroupEvent();
    
    @override
    List<Object> get props => [];
}

class HeightChanged extends PhhfGroupEvent
{
    const HeightChanged({required this.height});
    final String height;

    @override
    List<Object> get props => [height];
}

Handler:处理程序:

import 'package:equatable/equatable.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:myapp/models/statuses.dart';

part 'phhfgroup_event.dart';
part 'phhfgroup_state.dart';

class PhhfGroupBloc extends Bloc<PhhfGroupEvent, PhhfGroupState>
{
    PhhfGroupBloc() : super()
    {
        on<HeightChanged>(_mapHeightEventToState);
    }
    
    void _mapHeightEventToState(HeightChanged event, Emitter<PhhfGroupState> emit)
    {
        if(event.height.isEmpty)
        {
            emit(this.state.copyWith(
                height: null,
                heightStatus: FieldStatus.empty
            ));
        }
        
        else
        {
            double? height = double.tryParse(event.height);
            
            if(height == null)
                emit(this.state.copyWith(
                    height: null,
                    heightStatus: FieldStatus.nonnumeric
                ));
            
            else emit(this.state.copyWith(
                height: height,
                heightStatus: FieldStatus.numeric
            ));
        }
    }
}

Thanks !谢谢 !

By using freeze , you could do as follow:通过使用freeze ,您可以执行以下操作:

void main() {
  var person = Person('Remi', 24);

  // `age` not passed, its value is preserved
  print(person.copyWith(name: 'Dash')); // Person(name: Dash, age: 24)
  // `age` is set to `null`
  print(person.copyWith(age: null)); // Person(name: Remi, age: null)
}

If you don't want to use another package, I suggest to add an argument for controlling nullable values.如果您不想使用另一个 package,我建议添加一个用于控制可空值的参数。

class PhhfGroupState extends Equatable
{
    final double? height;
    final FieldStatus heightStatus;
    
    const PhhfGroupState({this.height, this.heightStatus = FieldStatus.initial});
    
    @override
    List<Object?> get props => [height, heightStatus];
    
    PhhfGroupState copyWith({double? height, FieldStatus? heightStatus, bool clearHeight = false})
    {
        return PhhfGroupState(
            height: clearHeight == true ? null : height ?? this.height,
            heightStatus: heightStatus ?? this.heightStatus
        );
    }
}

If you have a bunch of nullable fields, I would strongly recommend freeze , but for others, just add a flag for It.如果你有一堆可以为nullable的字段,我强烈推荐freeze ,但对于其他人,只需为它添加一个标志。

Thanks a lot because it is exactly what I need.非常感谢,因为这正是我所需要的。 Avoid lots of boilerplate code to achieve this simple goal...避免大量样板代码来实现这个简单的目标......

So to achieve what I need I will use:所以为了实现我需要的东西,我将使用:

  • freeze to help manage state / events冻结以帮助管理 state / 事件
  • my FieldStatus enum to make some informations available in the view我的 FieldStatus 枚举以在视图中提供一些信息

Another way, you can use ValueGetter .另一种方式,您可以使用ValueGetter

For example, password below:例如下面的password

@immutable
class LoginPageState {
  const LoginPageState({
    this.phone,
    this.password,
  });

  final String? phone;
  final String? password;

  LoginPageState copyWith({
    String? phone,
    ValueGetter<String?>? password,
  }) {
    return LoginPageState(
      phone: phone ?? this.phone,
      password: password != null ? password() : this.password,
    );
  }
}

Set password to null :password设置为null

void resetPassword() {
  final newState = state.copyWith(password: () => null);
  emit(newState);
}

You don't need any extra flag.你不需要任何额外的标志。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM