More data!
First, I add more data to my database. Just to make things more realistic. For each cinema I add a subcollection movies
in which I add some movies
. Each movie has this info
name: string,
runtime: string,
genre: string,
release_date: timestamp
In Firestore, data can also have different structure (NoSQL's power!) but, for simplicity, I follow the canonical way.
I add one movie for the first cinema and two movies for the second one.
Fetching the subcollection
I make the cinemas list clickable, so when I click an item I load movies scheduled for that specific cinema. To do this, I create a function selectCinema
that will perform a new query
to fetch a specific subcollection.
...
const selectCinema = (cinema) => {
database.collection('cinemas').doc(cinema.id).collection('movies').get()
.then(response => {
response.forEach(document => {
// access the movie information
});
})
.catch(error => {
setError(error);
});
}
..
{cinemas.map(cinema => (
<li key={cinema.id} onClick={() => selectCinema(cinema)}>
<b>{cinema.name}</b> in {cinema.city} has {cinema.total_seats} total seats
</li>
))}
At this point is easy managing the show/hide logic with React using the state
.
import React, { useState, useEffect } from 'react'; | |
import firebase from 'firebase'; | |
const firebaseConfig = { | |
apiKey: "AIzaSyDQXMsyejsUgPj-1ZPIyL9YMKdhZ280Mwo", | |
authDomain: "cinema-schedule-7bfa4.firebaseapp.com", | |
databaseURL: "https://cinema-schedule-7bfa4.firebaseio.com", | |
projectId: "cinema-schedule-7bfa4", | |
storageBucket: "cinema-schedule-7bfa4.appspot.com", | |
messagingSenderId: "215540682675", | |
appId: "1:215540682675:web:6e6e792cb9f041ae8e05c6" | |
}; | |
// Initialize Firebase | |
firebase.initializeApp(firebaseConfig); | |
const database = firebase.firestore(); | |
const App = () => { | |
const [cinemas, setCinemas] = useState([]); | |
const [selectedCinema, setSelectedCinema] = useState(); | |
const [movies, setMovies] = useState([]); | |
const [error, setError] = useState(); | |
const selectCinema = (cinema) => { | |
setSelectedCinema(cinema); | |
database.collection('cinemas').doc(cinema.id).collection('movies').get() | |
.then(response => { | |
const fetchedMovies = []; | |
response.forEach(document => { | |
const fetchedMovie = { | |
id: document.id, | |
...document.data() | |
}; | |
fetchedMovies.push(fetchedMovie); | |
}); | |
setMovies(fetchedMovies); | |
}) | |
.catch(error => { | |
setError(error); | |
}); | |
} | |
const timestampToString = (timestamp) => { | |
return Date(timestamp).toString(); | |
} | |
useEffect(() => { | |
database.collection('cinemas').get() | |
.then(response => { | |
const fetchedCinemas = []; | |
response.docs.forEach(document => { | |
const fetchedCinema = { | |
id: document.id, | |
...document.data() | |
}; | |
fetchedCinemas.push(fetchedCinema); | |
}); | |
setCinemas(fetchedCinemas); | |
}) | |
.catch(error => { | |
setError(error); | |
}); | |
}, []); | |
return ( | |
<div> | |
{error ? ( | |
<p>Ops, there is an error :(</p> | |
) : null} | |
<ul> | |
{cinemas.map(cinema => ( | |
<li key={cinema.id} onClick={() => selectCinema(cinema)}> | |
<b>{cinema.name}</b> in {cinema.city} has {cinema.total_seats} total seats | |
</li> | |
))} | |
</ul> | |
{selectedCinema ? ( | |
<ul> | |
{movies.map(movie => ( | |
<li key={movie.id}> | |
<b>{movie.name}</b> | {movie.genre} | {movie.runtime} | {timestampToString(movie.release_date)} | |
</li> | |
))} | |
</ul> | |
) : null} | |
</div> | |
); | |
} | |
export default App; |
A working demo
Gaunt but working.
Top comments (2)
Associating a hook with query will cause infinite rerendering of the component ,as useState will rerender the component ,which will lead to reexecute the Query .I think this is really a bad practice
Hello,
and what is your solution for this case?
Thanks!