Riverpod,在 BuildContext 和 Provider 之外读取状态

天神

我正在努力弄清楚为什么这不起作用(而不是说明它应该起作用的文档)。

我有一个像这样的提供者

import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:putin_flutter_client/api/client.dart';
import 'package:putin_flutter_client/api/storage.dart';

final userProvider = StateNotifierProvider((_) => UserNotifier());

class UserNotifier extends StateNotifier<UserState> {
  UserNotifier() : super(UserState());

  set username(String username) {
    state = UserState(username: username, password: state.password, jwt: state.jwt);
    secureStorageWrite('username', username);
  }

  set password(String password) {
    state = UserState(username: state.username, password: password, jwt: state.jwt);
    secureStorageWrite('password', password);
  }

  set jwt(String jwt) {
    state = UserState(username: state.username, password: state.password, jwt: jwt);
    Client.jwt = jwt;
    secureStorageWrite('jwt', jwt);
  }

  String get jwt {
    return state.jwt;
  }

  Future<void> initState() async {
    final user = await UserState.load();
    state.username = user.username;
    state.password = user.password;
    state.jwt = user.jwt;
  }
}

class UserState {
  String username;
  String password;
  String jwt;

  UserState({
    this.username,
    this.password,
    this.jwt,
  });

  static Future<UserState> load() async {
    return UserState(
      username: await secureStorageRead('username'),
      password: await secureStorageRead('password'),
      jwt: await secureStorageRead('jwt'),
    );
  }
}

最终深入一些小部件,这样的事情会更新状态

// usilizing the setter on the provider to update the state...
user.jwt = data['token'];

现在在代码的其他部分我管理 http 客户端。这显然无法访问BuildContext等,因此我执行以下操作以从存储状态中检索 jwt 值。

import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:http/http.dart' as http;
import 'package:putin_flutter_client/state/user.dart';

class Client extends http.BaseClient {
  final http.Client _client = http.Client();

  Future<http.StreamedResponse> send(http.BaseRequest request) {
    // Get the container as per riverpod documentation
    final container = ProviderContainer();
    // Access the value through the getter on the provider
    final jwt = container.read(userProvider).jwt;

    request.headers['user-agent'] = 'myclient::v1.0.0';
    request.headers['Content-Type'] = 'application/json';
    if (jwt != null) {
      request.headers['X-Auth-Token'] = jwt;
    }
    return _client.send(request);
  }
}

这始终为空,并且 UserState 几乎为空(所有成员都为空)。

Riverpod 文档中,它说这应该有效

test('counter starts at 0', () {
  final container = ProviderContainer();

  StateController<int> counter = container.read(counterProvider);
  expect(counter.state, 0);
});

有人可以帮我弄清楚上面的例子有什么问题吗?

贻贝

ProviderContainer() 为您的提供者创建一个新实例,它不会获得实际状态。您需要让您的客户端依赖于这样的用户状态:

final clientProvider = Provider<Client>((ref){
    return Client(ref.watch(userProvider.state))
});
class Client extends http.BaseClient {
  Client(this._userState);
  final UserState _userState;
  final http.Client _client = http.Client();

  Future<http.StreamedResponse> send(http.BaseRequest request) {
    
    final jwt = _userState.jwt;

    request.headers['user-agent'] = 'myclient::v1.0.0';
    request.headers['Content-Type'] = 'application/json';
    if (jwt != null) {
      request.headers['X-Auth-Token'] = jwt;
    }
    return _client.send(request);
  }
}

当您的用户状态发生变化时,客户端将使用新值重新实例化

如果您不想每次都重新实例化,则改为通过 read 方法:

final clientProvider = Provider<Client>((ref){
    return Client(ref.read)
});
class Client extends http.BaseClient {
  Client(this._reader);
  final Reader _reader;
  final http.Client _client = http.Client();

  Future<http.StreamedResponse> send(http.BaseRequest request) {
    
    final jwt = _reader(userProvider.state).jwt;

    request.headers['user-agent'] = 'myclient::v1.0.0';
    request.headers['Content-Type'] = 'application/json';
    if (jwt != null) {
      request.headers['X-Auth-Token'] = jwt;
    }
    return _client.send(request);
  }
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

Java Spring Security和OpenId Provider

NoClassDefFoundError:javax / inject / Provider和ClassNotFoundException:javax.inject.Provider

BuildContext与状态上下文

从子级更改状态时,小部件不使用Riverpod重建

如何在有状态或无状态窗口小部件之外访问BuildContext?

在构建函数之外使用BuildContext

如何使用本地存储,React Hook和Context Provider保持状态持久性

Flutter:可重用的小部件和BuildContext

Provider和ChangeNotifierProvider之间的区别

Riverpod:是否存在在另一个StreamProvider中读取StreamProvider的正确方法?

使用自定义ChangeNotifier初始化riverpod Provider

坏状态Flutter使用FutureBuilder和Provider中没有任何元素

Flutter Riverpod context.read与Provider在构建方法中

使用RiverPod状态管理颤抖地更改文本值

我有一个关于在“ Widget build(BuildContext context){}”之外的函数中初始化提供程序的问题。

柜台应用之外的简单Riverpod示例:两个单元的总和

如何在Riverpod中访问statenotifier内部的值和函数

如何在TextFormFields上使用Flutter_Riverpod和TextEditingControllers避免markNeedsBuilder()错误?

删除特定小部件 | Flutter 和 Riverpod

我想初始化状态。( RiverPod : StateNotifier )

您应该将状态值放在 Riverpod 的什么位置?

如何在更新状态通知程序 Riverpod 中的状态之前获取旧状态?

Flutter Firebase authStateChanges() 与 Provider 和 NullSafety On

我想使用 pull 刷新从 Riverpod 模型提供者构建的 Listview,该提供者从 Future Provider 获取数据

如何使用 GestureDetector 和 RiverPod 更改容器颜色

Riverpod:為什麼使用 Provider 而不是全局最終變量

Provider 和 setstate 哪個更貴?

在小部件类之外访问 Riverpod 1 方法

Riverpod / Flutter 中的现有状态编辑