2

I have a problem getting state data in the render function. It works fine and returns the array when I use

console.log(items)

But trying to get first item from the array yields an error

console.log(items[0])

Full code is:

import React from "react";
import StatsSection from "./../components/StatsSection";
import { db } from "./../util/database";

class IndexPage extends React.Component {

  constructor(props) {
    console.log(props)
    super(props);
    this.state = {};
  }

  componentDidMount() {

    var data = []
    db.collection('test')
      .get().then(snapshot => {
        snapshot.forEach(doc => {
          data.push(doc.data())
        })
      })

    this.setState({
      items: data
    });    
  }

  render() {
    const { items } = this.state
    console.log(items[0])


    return (

      <StatsSection
        color="white"
        size="medium"
        backgroundImage=""
        backgroundImageOpacity={1}
        items={[

          {
            title: "Following",
            stat: "123"
          },
          {
            title: "Followers",
            stat: "456k"
          },
          {
            title: "Likes",
            stat: "789"
          }
        ]}
      />
    );
  }
}

export default IndexPage;

Where am I making the mistake?

Tony Ngo
  • 14,681
  • 4
  • 21
  • 48
Tomas Batrla
  • 143
  • 1
  • 12
  • Can you show us how your data look like – Tony Ngo Nov 14 '19 at 00:25
  • Does this answer your question? [How do I return the response from an asynchronous call?](https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) – James Nov 14 '19 at 00:30
  • @TonyNgo my console output is: (1) […] ​0: Object { stat: "999", title: "Title" } ​length: 1 : Array [] main.5b640047.chunk.js:1:2202 – Tomas Batrla Nov 14 '19 at 08:08
  • Ok, so I managed to solve this. The problem was as @James stated in the asynchronous call. The render function was called twice. First when the page was loading and the second time when data from firestore was ready. I made a checking if this.state != null and now it works. Not the best solution, but it works ok. – Tomas Batrla Nov 14 '19 at 16:25

2 Answers2

1

You're only setting one item, so items is actually just one item and items[0] fails.

this.setState({
  items: data
});    

should be inside the .then() so that it only runs after all the items are populated with the .forEach().

Colin Ricardo
  • 12,717
  • 8
  • 30
  • 61
  • This is good remark, thanks for that. I changed it according your code. But in my particular scenario the result is the same. Trying to log whole array works fine, but trying to access only one item results in the error ... TypeError: "e is undefined" . Which is quite noninformative :/ – Tomas Batrla Nov 14 '19 at 08:16
  • Ok, so I managed to solve this. The problem was as @James stated in the asynchronous call. The render function was called twice. First when the page was loading and the second time when data from firestore was ready. I made a checking if this.state != null and now it works. Not the best solution, but it works ok. – Tomas Batrla Nov 14 '19 at 16:27
1

Update your componentDidMount() like so:

componentDidMount() {
  db.collection('test').get().then(snapshot => {
    var data = []
    snapshot.forEach(doc => {
      data.push(doc.data())
    })
    this.setState({ items: data })  
  })
}
Georgios
  • 3,317
  • 24
  • 38
Dillan Wilding
  • 713
  • 7
  • 21
  • Thans for your solution. I tried it,but the result is all the same. I am able to log full array correctly, but not the one specific item so I can actually use it in the template. – Tomas Batrla Nov 14 '19 at 08:21
  • What is the structure of your data? – Dillan Wilding Nov 14 '19 at 13:21
  • Ok, so I managed to solve this. The problem was as @James stated in the asynchronous call. The render function was called twice. First when the page was loading and the second time when data from firestore was ready. I made a checking if this.state != null and now it works. Not the best solution, but it works ok. – Tomas Batrla Nov 14 '19 at 16:27
  • That's a good point. I was still operating on the assumption that the page was functional before the request. Glad you solved it. – Dillan Wilding Nov 14 '19 at 17:03