从Firebase获取数据在initState中不起作用,Flutter。

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

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&lt;reviewWriteHome&gt; {
  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(&quot;user&quot;).doc(&quot;user&quot;).get();
    final pos = (userSnap.data() as Map&lt;String, dynamic&gt;);
    setState(() {
      userName = pos;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
          child: Center(
        child: Column(
          children: [
            const SizedBox(height: 30),
            Text(userName[&quot;username&quot;].toString()),
            const SizedBox(height: 10),
            GestureDetector(
              child: Image.asset(&#39;assets/image.png&#39;),
              onTap: () {
                Navigator.push(context, MaterialPageRoute(builder: (context) =&gt; 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&lt;DocumentSnapshot&lt;Map&lt;String, dynamic&gt;&gt;&gt;(
        future: FirebaseFirestore.instance.collection(&quot;user&quot;).doc(&quot;user&quot;).get(), // Call your future function directly here
        builder: (_, snapshot) {
          if (snapshot.hasError) return Text(&#39;Error = ${snapshot.error}&#39;);
          if (snapshot.connectionState == ConnectionState.waiting) {
            return const Text(&quot;Loading&quot;);
          }
          Map&lt;String, dynamic&gt; data = snapshot.data!.data()!;
          return Text(data[&#39;username&#39;]); 
        },
      )),
    );
  }

Update:

  @override
  void initState() {
    FirebaseFirestore.instance.collection(&quot;user&quot;).doc(&quot;user&quot;).get()
        .then((value) {
      setState(() {
        name = value.data()?[&#39;username&#39;];
      });
    });
    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`,你尝试在其上调用`[&quot;username&quot;]`,这是无效的。这正是错误消息告诉你的事情。

解决这个问题的一种简单方法是在加载用户名称时显示加载指示器:

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[&quot;username&quot;].toString())

Since username is null initially, you're trying to call [&quot;username&quot;] 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[&quot;username&quot;].toString()) : const CircularProgressIndicator()

huangapple
  • 本文由 发表于 2023年3月8日 16:55:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/75671028.html
匿名

发表评论

匿名网友

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

确定