Reputation:
I have seen in multiple places people placing the listener code inside the componentDidMount
, however, I am wondering how does it work since componentDidMount
is called only once, therefor, it should fetch only once. How does it fetches again when changes happen in Firestore?
Example code :
componentDidMount() {
if(this.state.screen === 7){
var query = firestore().collection('Collection').doc().collection('subcollection');
query = query.where('act', '==', 1);
query = query.where('city', '==', this.state.selected_city);
query = query.orderBy('update_time', 'desc');
query = query.limit(10);
query.onSnapshot({
error: (e) => this.setState({ errorMessage: e, refreshingPatients: false }),
next: (querySnapshot) => {
var dataSource = querySnapshot.docs.map(doc => { return { ...doc.data(), doc_id: doc.id } });
var lastVisiblePatient = dataSource[dataSource.length - 1].doc_id;
this.setState({
dataSource: dataSource,
lastVisiblePatient: lastVisiblePatient,
refreshingPatients: false,
});
},
});
}
}
EDIT: added an example code. I want to listen to changes of Firestore DB all the time. Is that the correct way of doing it? If yes, how does it work because componentDidMount
is only called once?
Note: I am only listening to Firestore when screen state is set to 7.
Upvotes: 1
Views: 2648
Reputation: 1240
Solution1: Read the comment inside the code.
componentDidUpdate(prevState, prevProps) {
if(prevState !== this.state.screen && this.state.screen === 7) {
var query = firestore().collection('Collection').doc().collection('subcollection');
query = query.where('act', '==', 1);
query = query.where('city', '==', this.state.selected_city);
query = query.orderBy('update_time', 'desc');
query = query.limit(10);
query.onSnapshot({
error: (e) => this.setState({ errorMessage: e, refreshingPatients: false }),
next: (querySnapshot) => {
var dataSource = querySnapshot.docs.map(doc => { return { ...doc.data(), doc_id: doc.id } });
var lastVisiblePatient = dataSource[dataSource.length - 1].doc_id;
this.setState({
// you are not updating screen so it is always 7
// if you update other state variables, it will trigger ComponentDidUpdate again,
// and again and again and again
dataSource: dataSource,
lastVisiblePatient: lastVisiblePatient,
refreshingPatients: false,
});
},
});
}
}
By adding prevState !== this.state.screen
, you can prevent componentDidUpdate
being triggered everytime you update other states.
Like dataSource, lastVisiblePatient, and refreshingPatients.
Solution 2: Since you are using class components, you can use setState callback.
this.setState({screen: newValue}, doSomethingNew);
doSomethingNew(){
if (this.state.screen === 7) {
// your code goes here
}
}
the callback function(here doSomethingNew
) is triggered after screen
value is updated with newValue
.
Solution3: If you convert to function component, you can use useEffect
dependency.
const [screen, setScreen] = useState(initialValue);
useEffect(() => {
if (screen === 7) {
//do something here
}
}, [screen]); // adding screen as a dependency means this useEffect is triggered only when screen value is changed.
Upvotes: 0
Reputation: 599776
Your componentDidMount
is indeed only called once, but you're attaching a permanent listener in there. So the handler that you specify in onSnapshot.next
is called right away with the initial data from the database, and after that each time that the data matching the query changes.
Upvotes: 1