问题
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?
回答1:
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!
回答2:
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>
)
}
}
回答3:
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()
}
Read More About Promises
=======================EDIT=========================
getMyStory().then((snapshot) => {
const listItems = snapshot.map((element) =>
<li>{element}</li>
);
ReactDOM.render(
<ul>{listItems}</ul>,
document.getElementById('root')
);
});
Read More About Map
回答4:
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;
来源:https://stackoverflow.com/questions/52880387/fetching-data-from-firestore