Flutter BLoC如何在设置一个变量时持久化状态。

huangapple go评论93阅读模式
英文:

Flutter BLoC how to persist state when setting one variable

问题

我有一个包含多个变量的状态

我使用setter state更改状态,但每次我使用setter state更改状态时,变量都会重置为初始状态

这是我的状态

const AuthSignInState({
    this.signUpType = 'email',
    this.errorMessage = '',
    this.errorSignIn = false,
    this.isLoading = false,
    this.currentUser = '',
    this.user,
});

final String errorMessage;
final bool errorSignIn;
final String signUpType;
final bool isLoading;
final String currentUser;
final Sync? user;
}

这是我的setter state,例如,我想在触发此状态时更改signuptype,但其他变量将重置为初始值,如何在设置一个变量后仍然保持状态不变

class SetSignInTypeState extends AuthSignInState {
  final String type;
  const SetSignInTypeState({required this.type}) : super(signUpType: type);

  @override
  List<Object?> get props => [type];
}
英文:

I have a state with multiple variables

im changing the state with setters state but every time i change the state with setter state variables reset to initial state

here is my state

const AuthSignInState({
 this.signUpType = &#39;email&#39;,
 this.errorMessage = &#39;&#39;,
 this.errorSignIn = false,
 this.isLoading = false,
 this.currentUser = &#39;&#39;,
 this.user,
});

final String errorMessage;
final bool errorSignIn;
final String signUpType;
final bool isLoading;
final String currentUser;
final Sync? user;
}

here is my setter state for example i want to change the signuptype when i trigger this state other variables will reset to the initial value how can i persist the state even after setting one variable

class SetSignInTypeState extends AuthSignInState {
  final String type;
  const SetSignInTypeState({required this.type}) : super(signUpType: type);

  @override
  List&lt;Object?&gt; get props =&gt; [type];
}

答案1

得分: 0

因为setter状态正在使用更新后的值创建状态类的新实例。这意味着旧的状态类实例被丢弃,其所有值都丢失。

您可以使用ChangeNotifierStreamController来在设置一个变量后持久化状态。

1)使用ChangeNotifier

class AuthSignInState extends ChangeNotifier {
  AuthSignInState({
    this.signUpType = 'email',
    this.errorMessage = '',
    this.errorSignIn = false,
    this.isLoading = false,
    this.currentUser = '',
    this.user,
  });

  String signUpType;
  String errorMessage;
  bool errorSignIn;
  bool isLoading;
  String currentUser;
  Sync? user;

  void setSignUpType(String type) {
    this.signUpType = type;
    notifyListeners();
  }
}

在这段代码中,setSignUpType()方法设置signUpType变量,然后调用notifyListeners()方法通知其侦听器状态已更改。这确保UI将更新以反映signUpType变量的新值。

2)使用StreamController

class AuthSignInState {
  final String errorMessage;
  final bool errorSignIn;
  final String signUpType;
  final bool isLoading;
  final String currentUser;
  final Sync? user;

  final StreamController<AuthSignInState> _controller =
      StreamController<AuthSignInState>();

  AuthSignInState({
    this.signUpType = 'email',
    this.errorMessage = '',
    this.errorSignIn = false,
    this.isLoading = false,
    this.currentUser = '',
    this.user,
  });

  Stream<AuthSignInState> get stream => _controller.stream;

  void setSignUpType(String type) {
    this.signUpType = type;
    _controller.sink.add(this);
  }
}

在上面的代码中,setSignUpType()方法设置signUpType变量,然后向_controller流添加一个新事件。这个事件将被发射到流的所有侦听器,然后它们会相应地更新其UI。

如果有帮助,请告诉我。

英文:

It is because the setter state is creating a new instance of the state class with the updated values. This means that the old instance of the state class is discarded and all of its values are lost.

You can use ChangeNotifier or StreamController to persist the state even after setting one variable.

  1. By ChangeNotifier

    class AuthSignInState extends ChangeNotifier {
      const AuthSignInState({
          this.signUpType = &#39;email&#39;,
          this.errorMessage = &#39;&#39;,
          this.errorSignIn = false,
          this.isLoading = false,
          this.currentUser = &#39;&#39;,
          this.user,
      });
    
      final String errorMessage;
      final bool errorSignIn;
      final String signUpType;
      final bool isLoading;
      final String currentUser;
      final Sync? user;
    
      void setSignUpType(String type) {
          this.signUpType = type;
          notifyListeners();
      }
    }
    

In this code, the setSignUpType() method sets the signUpType variable and then calls the notifyListeners() method to notify its listeners that the state has changed. This ensures that the UI will be updated to reflect the new value of the signUpType variable.

  1. By StreamController

    class AuthSignInState {
         final String errorMessage;
         final bool errorSignIn;
         final String signUpType;
         final bool isLoading;
         final String currentUser;
         final Sync? user;
    
         final StreamController&lt;AuthSignInState&gt; _controller =
               StreamController&lt;AuthSignInState&gt;();
    
         AuthSignInState({
           this.signUpType = &#39;email&#39;,
           this.errorMessage = &#39;&#39;,
           this.errorSignIn = false,
           this.isLoading = false,
           this.currentUser = &#39;&#39;,
           this.user,
    });
    
        Stream&lt;AuthSignInState&gt; get stream =&gt; _controller.stream;
    
        void setSignUpType(String type) {
           this.signUpType = type;
           _controller.sink.add(this);
       } 
    }
    

In the above code, the setSignUpType() method sets the signUpType variable and then adds a new event to the _controller stream. This event will be emitted to all of the listeners of the stream, which will then update their UI accordingly.

Let me know if this helps.

答案2

得分: 0

为保留所有值并仅更改其中一个(或少数几个)值,通常会使用copyWith等方法。然后,您可以创建一个具有旧对象所有值的新实例,并在该函数的参数中指定更改。使用freezed包(https://pub.dev/packages/freezed)可以轻松实现这一点。在pub.dev上查看它,这里也是Flutter团队对此包功能的简要解释https://youtu.be/RaThk0fiphA

一般来说,实现看起来像这样:

@freezed
class AuthSignInState with _$AuthSignInState {
  const factory AuthSignInState({
    final String errorMessage,
     required bool errorSignIn,
     required String signUpType,
     required bool isLoading,
     required String currentUser,
     required Sync? user,
  }) = _AuthSignInState;
}

然后,在使用build_runner生成您的代码之后,在您的bloc中会有:

emit(state.copyWith(signUpType: newSignUpType));

Freezed是更高效且耗时更少的解决方案,用于更改对象的属性。希望这对您有所帮助。

英文:

To preserve all values and change only one (or few) of them, it's common to use methods like copyWith. Then you create a new instance of an object with all the values of the old one, with changes specified in arguments of that function. It is made very easy with freezed package (https://pub.dev/packages/freezed). Checkout it on pub.dev and also here is Flutter's team short explanation of this package's capabilities https://youtu.be/RaThk0fiphA

In general the implementation looks like this:

@freezed
class AuthSignInState with _$AuthSignInState {
  const factory AuthSignInState({
    final String errorMessage,
     required bool errorSignIn,
     required String signUpType,
     required bool isLoading,
     required String currentUser,
     required Sync? user,
  }) = _AuthSignInState;
}

Then, after generating your code with build_runner, you would have in your bloc:

emit(state.copyWith(signUpType: newSignUpType));

Freezed is an efficient and less time consuming solution to change properties of an object. Hope that helps.

huangapple
  • 本文由 发表于 2023年8月10日 18:49:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/76875023.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定