4

I'm reading data from firestore and stores it in state array of objects.

when i

console.log(this.state.array)

it returns the whole array with all the data of the objects, but when i

console.log(this.state.array.name)

or

console.log(this.state.array[0])

it returns undefined

.

I have tried to get the data with

forEach

loop but it seems to be not working as well.

    constructor(props) {
        super(props);
        this.state = { tips: [] };
    }

    componentDidMount() {
        firebase.firestore().collection('pendingtips').get()
            .then(doc => { 
                doc.forEach(tip => { 
                    this.setState([...tips], tip.data()); 
                    console.log(this.state.tips);
                }); 
            })
            .catch(() => Alert.alert('error'));
    }

    renderTips() {
        console.log(this.state.tips); //returns the whole array as expected
        console.log(this.state.tips[0].name); //returns undefined
        return this.state.tips.map(tip => <PendingTip key={tip.tip} name={tip.name} tip={tip.tip} />); //return null because tip is undefined
    } 
   render() {
        return (
            <View style={styles.containerStyle}>
                <ScrollView style={styles.tipsContainerStyle}>
                    {this.renderTips()}
                </ScrollView>
            </View>
        );
    }

the array structure is:

"tips": [
    { name: "X", tip: "Y" },
    { name: "Z", tip: "T" }
]

so I expect this.state.tips[0].name will be "X" instead of undefined.

thanks in advance.

1
  • Can you share print screen of this array in beakpoint? Commented Jul 27, 2019 at 12:51

3 Answers 3

1
  1. First of all you should fetch data in componentDidMount instead of componentWillMount.

https://reactjs.org/docs/faq-ajax.html#where-in-the-component-lifecycle-should-i-make-an-ajax-call

  1. Secondly, you should use this.setState to update your state, instead of mutating it directly.
  componentDidMount() {
    firebase
      .firestore()
      .collection("pendingtips")
      .get()
      .then(docs => {
        const tips = docs.map(doc => doc.data());

        this.setState({ tips });
      })
      .catch(() => Alert.alert("error"));
  }
Sign up to request clarification or add additional context in comments.

2 Comments

can you show us your render method? not renderTips
Changed it to ComponentDidMount but the main problem is with the state array, the this.state.array.push(object) actually worked for me. the problem was that I couldn't fetch the data from the state array properly
1

I Found out that the problem was that JavaScript saves arrays as objects. for example this array:

[ 'a' , 'b' , 'c' ]

is equal to:

{
  0: 'a',
  1: 'b',
  2: 'c',
  length: 3
}

"You get undefined when you try to access the array value at index 0, but it’s not that the value undefined is stored at index 0, it’s that the default behavior in JavaScript is to return undefined if you try to access the value of an object for a key that does not exist." as written in this article

Comments

0

firesore requests are async, so by time your request gets execute your component is getting mounted and in a result you are getting undefined for your state in console.

You must do API call in componentDidMount instead of componentWillMount.

Mutating/changing state like this, will not trigger re-render of component and your component will not get latest data,

doc.forEach(tip => { 
      this.state.tips.push(tip.data()); 
      console.log(this.state.tips);
}); 

You must use setState to change your state, doing this your component will get re-render and you have latest data all the time.

componentDidMount(){
  firebase.firestore().collection('pendingtips').get()
     .then(doc => { 
         const tipsData = doc.map(tip => tip.data());
         this.setState({tips:tipsData},() => console.log(this.state.tips));
     })
     .catch(() => Alert.alert('error'));
}

While calling renderTips function make sure your state array has data,

{this.state.tips.length > 0 && this.renderTips()}

8 Comments

doesn't work as well... passing me straight to .catch
Changed it to ComponentDidMount but the main problem is with the state array, the this.state.array.push(object) actually worked for me. the problem was that I couldn't fetch the data from the state array proparly
You can do this, {this.state.tips.length > 0 && this.renderTips()}
What console.log(this.state.tips) print's?
Also try to print doc in your API response.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.