Reputation: 481
So I am trying to fetch data from Firestore, when I console log it I got the content of my collection back, but when I move the code to a function I am not able to return it back.
This code works:
const db = firebase.firestore();
db.settings({ timestampsInSnapshots: true});
db.collection('story').get().then((snapshot) => {
snapshot.docs.forEach(doc => {console.log(doc.data())
;})
})
This doesnt work. (it compiles, but doesn`t return anything):
...
getMyStory = () => {
const db = firebase.firestore();
db.settings({ timestampsInSnapshots: true});
db.collection('story').get().then((snapshot) => {
snapshot.docs.forEach(doc => {
let items = doc.data();
})
});
return this.items;
}
render () {
return (
<p>{this.getMyStory}</p>
);
}
What am I doing wrong?
Upvotes: 3
Views: 16793
Reputation: 147
if any one is using React with Redux with Firebase and has difficulty here is how to do it here i get all the publications from firestore using redux
// publicationsActions.js
var publicationsRef = db.collection("publications")
var publicationsList = []
// Function that returns the publications list
export const getPublications = () => async (dispatch) => {
await publicationsRef.get().then((res) => {
res.docs.forEach(doc => {
publicationsList.push(doc.data())
})
dispatch({
type: GET_PUBS,
payload: publicationsList
})
})
}
// publicationReducer.js
export default function (state = initialState, action) {
switch(action.type){
case GET_PUBS:
return {
...state,
items: action.payload
}
case ADD_PUB:
return {
...state,
items: [action.payload, ...state.items]
}
default:
return state;
}
}
Upvotes: 0
Reputation: 488
import React, { Component } from "react";
import firebase from "../config";
class App extends Component {
constructor(props) {
super(props);
// Reference firebase in this.state, creating a global key-value pair
this.state = {
roomsRef: firebase.firestore().collection("rooms"),
rooms: []
};
}
// Retrieve data from firebase and set state
getDb(db) {
db.get().then(querySnapshot => {
querySnapshot.forEach(doc => {
let room = doc.data();
room.key = doc.id;
this.setState({
rooms: this.state.rooms.concat(room)
});
});
});
}
//
componentDidMount() {
this.getDb(this.state.roomsRef);
}
render() {
const rooms = this.state.rooms.map((r, i) => <li key={i}>{r.name}</li>);
return (
<div className="App">
<section className="room-list">
{this.state.rooms.length === 0 ? (
<p>loading...</p>
) : (
<ul>{rooms}</ul>
)}
</section>
</div>
);
}
}
export default App;
Upvotes: 0
Reputation: 705
The Promise object represents the eventual completion (or failure) of an asynchronous operation, and its resulting value
Based in your code return this.items; executed first and then resolve db.collection('story').get(), finally never get the results.
Basically this line:
db.collection('story').get()
it's a promise then you must wait that resolve the result, below code:
getMyStory = () => {
const db = firebase.firestore();
db.settings({ timestampsInSnapshots: true});
return db.collection('story').get()
}
=======================EDIT=========================
getMyStory().then((snapshot) => {
const listItems = snapshot.map((element) =>
<li>{element}</li>
);
ReactDOM.render(
<ul>{listItems}</ul>,
document.getElementById('root')
);
});
Upvotes: 1
Reputation: 5818
The main problem here is that you are trying to render async data synchronously, which isn't possible to do with react (not yet at least).
When rendering async data you will usually leverage component state.
Below is a standard usage pattern when loading and rendering something async.
class YourComponent extends Component {
state = {
items: []
}
// This method is called when the component mounts
// Usually a good place to do async requests
componentDidMount() {
db.collection('story').get().then(snapshot => {
// After promise is finished set data to local state
// When setting state the render method will be called, thus rerendering the UI
this.setState({ items: snapshot })
})
}
render() {
// Access your items from local component state
const { items } = this.state;
return (
<div>
{items.forEach(doc => {
// Render whatever data is in your document
return <p key={doc.id}> { Your data goes here }</p>
})
}
</div>
)
}
}
Upvotes: 1
Reputation: 30390
Your rendering logic will need to account for the query to Firebase being asynchronous. Consider making use of your components state
to resolve this, by making the following adjustments to your code:
getMyStory() { /* Remove arrow function */
const db = firebase.firestore();
db.settings({ timestampsInSnapshots: true});
db.collection('story').get().then((snapshot) => {
snapshot.docs.forEach(doc => {
let items = doc.data();
/* Make data suitable for rendering */
items = JSON.stringify(items);
/* Update the components state with query result */
this.setState({ items : items })
});
});
}
Next, add componentDidMount()
to your component, and then add the call to getMyStory()
like so:
componentDidMount() {
/* Cause your component to request data from Firebase when
component first mounted */
this.getMyStory()
}
Finall, update your render method to use the state, rather than method:
render () {
return (<p>{ this.state.items || 'Loading' }</p>);
}
Hope this helps!
Upvotes: 10