
[英]Is is correct to use Future builder inside a streambuilder in Flutter
[英]Flutter use variable created inside Future builder outside of the build method,
我有一个未来的构建器女巫我用来获取数据,我需要使用我从 api 获得的文本编辑 controller 必须在构建之外定义,我需要提供文本编辑 Z594C103F2C6E04C3CD8AB0 的初始值,9031初始值我需要输入 data3.firstName 和 data3.lastName,现在初始值是硬编码的。
Future<Response> fetchAccountData() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String? authorization = prefs.getString('authorization');
var url = 'https://dev.api.wurk.skyver.co/api/v1/employees/account';
response1 = await http.get(
Uri.parse(url),
headers: <String, String>{
'authorization': authorization ?? basicAuth.toString()
},
);
return response1;
}
factory AccountData.fromJson(Map<String, dynamic> json) {
return AccountData(
firstName: json['firstName'],
lastName: json['lastName'],
phoneNumber: json['phoneNumber']);
}
}
Future<void> putAccountData() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String? authorization = prefs.getString('authorization');
var url = 'https://dev.api.wurk.skyver.co/api/v1/employees/account';
Map payload = {
"firstName": editedFirstName.text,
"lastName": editedLastName.text,
};
try {
final response = await http.put(Uri.parse(url),
headers: <String, String>{
'authorization': authorization ?? basicAuth.toString(),
"Content-Type": "application/json"
},
body: jsonEncode(payload));
} catch (er) {}
}
TextEditingController editedFirstName =
TextEditingController(text: 'firstName'); << needs to be data3.firstName
TextEditingController editedLastName =
TextEditingController(text: 'lastName');<< needs to be data3.lastName
return SafeArea(
child: WillPopScope(
onWillPop: () async {
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => const ProfileScreen(),
),
);
return shouldPop;
},
body: FutureBuilder<Response>(
future: futureData,
builder: (context, snapshot) {
if (snapshot.hasData) {
AccountData data3 = AccountData.fromJson( << data3 has data3.firstName, and
data3.lastName
json.decode(snapshot.data!.body),
);
您可以像这样使用后期初始化:
late TextEditingController editedFirstName;
late TextEditingController editedLastName;
return SafeArea(
child: WillPopScope(
onWillPop: () async {
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => const ProfileScreen(),
),
);
return shouldPop;
},
body: FutureBuilder<Response>(
future: futureData,
builder: (context, snapshot) {
if (snapshot.hasData) {
AccountData data3 = AccountData.fromJson( << data3 has data3.firstName, and
data3.lastName
json.decode(snapshot.data!.body),
);
editedFirstName = TextEditingController(text: data3.firstname)
editedLastName = TextEditingController(text: data3.lastname)
我不完全理解拥有全局 TextController 的原因(而且我认为这也不是一个好主意),但使用 Riverpod 它看起来像这样:
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
class AccountData {
final String firstName;
final String lastName;
final String phoneNumber;
AccountData({
required this.firstName,
required this.lastName,
required this.phoneNumber,
});
factory AccountData.fromJson(Map<String, dynamic> json) {
return AccountData(
firstName: json['firstName'],
lastName: json['lastName'],
phoneNumber: json['phoneNumber'],
);
}
}
Future<Map<String, dynamic>> fetchAccountData() async {
final response = {
'firstName': 'Name',
'lastName': 'LastName',
'phoneNumber': '98786758690',
};
return Future.delayed(const Duration(seconds: 3), () => response);
}
final futureData = FutureProvider<AccountData>((_) async {
final data = await fetchAccountData();
return AccountData.fromJson(data);
});
final firstNameController = ChangeNotifierProvider<TextEditingController>((ref) {
final controller = TextEditingController();
ref.listen<AsyncValue<AccountData>>(futureData, (_, curr) {
curr.whenOrNull(
data: (d) => controller.text = d.firstName,
);
});
return controller;
});
final lastNameController = ChangeNotifierProvider<TextEditingController>((ref) {
final controller = TextEditingController();
ref.listen<AsyncValue<AccountData>>(futureData, (_, curr) {
curr.whenOrNull(
data: (d) => controller.text = d.lastName,
);
});
return controller;
});
void main() {
runApp(const ProviderScope(child: MyApp()));
}
class MyApp extends StatelessWidget {
const MyApp();
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: MyWidget(),
),
),
);
}
}
class MyWidget extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final firstController = ref.watch(firstNameController.notifier);
final lastcontroller = ref.watch(lastNameController.notifier);
return ref.watch(futureData).when(
loading: () => const CircularProgressIndicator(),
error: (e, _) => TextButton(
child: Text('$e'),
onPressed: () => ref.refresh(futureData),
),
data: (_) {
return Column(
children: [
TextField(
controller: firstController,
),
TextField(
controller: lastcontroller,
),
]
);
}
);
}
}
现在跟随Hazar Belge使用后期初始化程序是一个好主意,如果没有 state 管理,这个想法将简单地使用 FutureBuilder,然后将数据传递给 StatefulWidget,后者使用该数据初始化 TextEditingControllers,然后再次使用 didUpdateWidget,所有这些都没有取决于外部 package (您的应用程序越大,您将需要使用更多包来帮助您快速开发,但我建议您尝试使用基本知识来掌握您可以使用框架做的所有事情)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.