英文:
data get from firebase in initstate not working, flutter
问题
我目前正在编写代码,在initState
中获取Firebase数据。但无论我做什么,它都不返回或不存储数据,所以我收到以下错误。
I'm currently writting a code to fetch a firebase data in initState.
But no matter what I do it does't return or doesn't store data so I get following error.
I'm getting error at code *Text(userName["username"].toString())*
> Exception has occurred. NoSuchMethodError (NoSuchMethodError: The
> method '[]' was called on null. Receiver: null Tried calling:
> []("username"))
Please teach me how to make it work.
Since I'm using setState inside of my code I would not like to use FutureBuilder nor StreamBuilder to perform it.
class _reviewWriteHomeState extends State<reviewWriteHome> {
var user = FirebaseAuth.instance.currentUser;
var userName;
String? userIcon;
@override
void initState() {
// TODO: implement initState
super.initState();
Future(() async {
fetchData();
await Future.delayed(Duration(seconds: 5));
});
}
Future fetchData() async {
final userSnap = await FirebaseFirestore.instance.collection("user").doc("user").get();
final pos = (userSnap.data() as Map<String, dynamic>);
setState(() {
userName = pos;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Center(
child: Column(
children: [
const SizedBox(height: 30),
Text(userName["username"].toString()),
const SizedBox(height: 10),
GestureDetector(
child: Image.asset('assets/image.png'),
onTap: () {
Navigator.push(context, MaterialPageRoute(builder: (context) => const newPage()));
},
)
],
),
)),
);
}
}
英文:
I'm currently writting a code to fetch a firebase data in initState.
But no matter what I do it does't return or does't store data so I get following error.
I'm getting error at code Text(userName["username"].toString())
> Exception has occurred. NoSuchMethodError (NoSuchMethodError: The
> method '[]' was called on null. Receiver: null Tried calling:
> )
Please teach me how to make it work.
Since I'm using setState inside of by code I would not like to use futurebuilder nor streambuilder to perform it.
class _reviewWriteHomeState extends State<reviewWriteHome> {
var user = FirebaseAuth.instance.currentUser;
var userName;
String? userIcon;
@override
void initState() {
// TODO: implement initState
super.initState();
Future(() async {
fetchData();
await Future.delayed(Duration(seconds: 5));
});
}
Future fetchData() async {
final userSnap = await FirebaseFirestore.instance.collection("user").doc("user").get();
final pos = (userSnap.data() as Map<String, dynamic>);
setState(() {
userName = pos;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Center(
child: Column(
children: [
const SizedBox(height: 30),
Text(userName["username"].toString()),
const SizedBox(height: 10),
GestureDetector(
child: Image.asset('assets/image.png'),
onTap: () {
Navigator.push(context, MaterialPageRoute(builder: (context) => const newPage()));
},
)
],
),
)),
);
}
}
答案1
得分: 1
在initState()
中使用future
并不是一个最佳的方法,你可以在initState
内部使用addPostFrameCallback
,或者在返回小部件树给build
方法之前使用它,而不必真的使用future builder。
以下是一个示例:
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
Future(() {
fetchData();
await Future.delayed(Duration(seconds: 5));
});
});
或者你可以使用FutureBuilder
。请参考BouncyBits的回答。
英文:
using future
in initState()
is not a best idea, you can use addPostFrameCallback
inside initState
, or use it before returning widget tree to the build
method
and you don't really have to use the future builder.
here is an example
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
Future(() {
fetchData();
await Future.delayed(Duration(seconds: 5));
});
});
or You can use FutureBuilder
. refer BouncyBits answer for that.
答案2
得分: 0
不建议在initState
中使用future
,而是使用FutureBuilder
。
更新后的代码:
@override
void initState() {
FirebaseFirestore.instance.collection("user").doc("user").get()
.then((value) {
setState(() {
name = value.data()?['username'];
});
});
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: name != null ? Text(name!) : const CircularProgressIndicator(),
),
);
}
请注意,我只提供了代码的翻译,没有其他内容。
英文:
It is not advised to use future
in initState
instead use the FutureBuilder
@override
void initState() {
// TODO: implement initState
super.initState();
// Future(() async { // Remove these
// fetchData();
// await Future.delayed(Duration(seconds: 5));
// });
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: FutureBuilder<DocumentSnapshot<Map<String, dynamic>>>(
future: FirebaseFirestore.instance.collection("user").doc("user").get(), // Call your future function directly here
builder: (_, snapshot) {
if (snapshot.hasError) return Text('Error = ${snapshot.error}');
if (snapshot.connectionState == ConnectionState.waiting) {
return const Text("Loading");
}
Map<String, dynamic> data = snapshot.data!.data()!;
return Text(data['username']);
},
)),
);
}
Update:
@override
void initState() {
FirebaseFirestore.instance.collection("user").doc("user").get()
.then((value) {
setState(() {
name = value.data()?['username'];
});
});
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child:
name != null ? Text(name!) : const CircularProgressIndicator())
);
}
}
答案3
得分: 0
你将 `userName` 声明为:
var userName;
由于你没有指定默认值,这意味着它的初始值是 `null`。因为只有在从Firestore获取数据(很多秒后)时才设置 `userName` 的值,所以UI将在 `userName` 仍然是 `null` 的情况下被渲染。在 `build` 方法中,你进行了以下操作:
Text(userName["username"].toString())
由于`username`最初是`null`,你尝试在其上调用`["username"]`,这是无效的。这正是错误消息告诉你的事情。
解决这个问题的一种简单方法是在加载用户名称时显示加载指示器:
userName != null ? Text(userName["username"].toString()) : const CircularProgressIndicator()
英文:
You declared userName
as:
var userName;
Since you don't specify a default value, that means that its initial value is null
. Since you only set the vale of userName
when you get data from Firestore (many seconds later), the UI will be rendered while userName
is still null
. And in the build
method you then do:
Text(userName["username"].toString())
Since username
is null
initially, you're trying to call ["username"]
on it, which isn't valid. And that's exactly what the error message tells you.
A simple way to solve this is to show a loading indicator while the user name is being loaded:
userName != null? Text(userName["username"].toString()) : const CircularProgressIndicator()
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论