Flutter Riverpod:如何实现 FutureProvider?
Posted
技术标签:
【中文标题】Flutter Riverpod:如何实现 FutureProvider?【英文标题】:Flutter Riverpod : How to Implement FutureProvider? 【发布时间】:2020-11-11 12:20:22 【问题描述】:我使用Flutter Riverpod 包来处理http 请求。我有简单的 Http get 请求来显示来自服务器的所有用户,我使用来自Flutter Riverpod 包的 FutureProvider 来管理它。
API
class UserGoogleApi
Future<List<UserGoogleModel>> getAllUser() async
final result = await reusableRequestServer.requestServer(() async
final response =
await http.get('$appConfig.baseApiUrl/$appConfig.userGoogleController/getAllUser');
final Map<String, dynamic> responseJson = json.decode(response.body);
if (responseJson['status'] == 'ok')
final List list = responseJson['data'];
final listUser = list.map((e) => UserGoogleModel.fromJson(e)).toList();
return listUser;
else
throw responseJson['message'];
);
return result;
用户提供者
class UserProvider extends StateNotifier<UserGoogleModel>
UserProvider([UserGoogleModel state]) : super(UserGoogleModel());
Future<UserGoogleModel> searchUserByIdOrEmail(
String idUser,
String emailuser,
String idOrEmail = 'email_user',
) async
final result = await _userGoogleApi.getUserByIdOrEmail(
idUser: idUser,
emailUser: emailuser,
idOrEmail: idOrEmail,
);
UserGoogleModel temp;
for (var item in result)
temp = item;
state = UserGoogleModel(
idUser: temp.idUser,
createdDate: temp.createdDate,
emailUser: temp.emailUser,
imageUser: temp.emailUser,
nameUser: temp.nameUser,
tokenFcm: temp.tokenFcm,
listUser: state.listUser,
);
return temp;
Future<List<UserGoogleModel>> showAllUser() async
final result = await _userGoogleApi.getAllUser();
state.listUser = result;
return result;
final userProvider = StateNotifierProvider((ref) => UserProvider());
final showAllUser = FutureProvider.autoDispose((ref) async
final usrProvider = ref.read(userProvider);
final result = await usrProvider.showAllUser();
return result;
);
设置完成后,我可以像这样调用 showAllUser :
Consumer((ctx, read)
final provider = read(showAllUser);
return provider.when(
data: (value)
return ListView.builder(
itemCount: value.length,
shrinkWrap: true,
itemBuilder: (BuildContext context, int index)
final result = value[index];
return Text(result.nameUser);
,
);
,
loading: () => const CircularProgressIndicator(),
error: (error, stackTrace) => Text('Error $error'),
);
),
如果http请求没有必填参数也没问题,但是如果我的http请求需要参数我就遇到了问题。我不知道如何处理。
假设,我有另一个 http get 来显示来自 id 用户或电子邮件用户的特定用户。然后 API 看起来像:
API
Future<List<UserGoogleModel>> getUserByIdOrEmail(
@required String idUser,
@required String emailUser,
@required String idOrEmail,
) async
final result = await reusableRequestServer.requestServer(() async
final baseUrl =
'$appConfig.baseApiUrl/$appConfig.userGoogleController/getUserByIdOrEmail';
final chooseURL = idOrEmail == 'id_user'
? '$baseUrl?id_or_email=$idOrEmail&id_user=$idUser'
: '$baseUrl?id_or_email=$idOrEmail&email_user=$emailUser';
final response = await http.get(chooseURL);
final Map<String, dynamic> responseJson = json.decode(response.body);
if (responseJson['status'] == 'ok')
final List list = responseJson['data'];
final listUser = list.map((e) => UserGoogleModel.fromJson(e)).toList();
return listUser;
else
throw responseJson['message'];
);
return result;
用户提供者
final showSpecificUser = FutureProvider.autoDispose((ref) async
final usrProvider = ref.read(userProvider);
final result = await usrProvider.searchUserByIdOrEmail(
idOrEmail: 'id_user',
idUser: usrProvider.state.idUser, // => warning on "state"
);
return result;
);
当我使用 usrProvider.state.idUser
从 userProvider 访问 idUser 时,我收到了这个警告。
The member 'state' can only be used within instance members of subclasses of 'package:state_notifier/state_notifier.dart'.
这与我在this 上的问题类似,但在那个问题上我已经知道使用read(userProvider.state)
解决了,但是在FutureProvider 中我无法使用ref(userProvider)
获得相同的结果。
我错过了什么?
【问题讨论】:
【参考方案1】:警告:这不是长期解决方案
假设您的 FutureProvider 在每次使用后都被正确处理,这应该是一个合适的解决方法,直到 Riverpod 的新更改生效。我做了一个快速测试看看,它确实有效。确保您定义了这样的 getter,并且不要覆盖 StateNotifier 定义的默认值。
class A extends StateNotifier<B>
...
static final provider = StateNotifierProvider((ref) => A());
getState() => state;
...
final provider = FutureProvider.autoDispose((ref) async
final a = ref.read(A.provider);
final t = a.getState();
print(t);
);
不理想,但似乎是一个很好的解决方法。我相信在外部无法访问状态的目的是确保状态操作由 StateNotifier 本身处理,因此在此期间使用 getter 不会是世界末日。
【讨论】:
在 Riverpod 文档上 riverpod.dev/docs/concepts/combining_providers 的标题 我可以在不听的情况下阅读提供程序吗? 开发人员告诉我们在任何情况下都不要使用.read()
在提供者
@MwBakker 这个问题/答案不再相关。在更新版本的riverpod 中不应再出现此问题。以上是关于Flutter Riverpod:如何实现 FutureProvider?的主要内容,如果未能解决你的问题,请参考以下文章