Cvičení: Firestore nákupní seznam
Úvod
Firestore je online databáze z balíčku služeb Firebase od Googlu, kterou volně můžete zapojit do vašich projektů. Vaši uživatelé pak budou mít přístup k těm nejčerstvějším datům podobně jako když stahují pomocí fetch
. Zároveň jim můžete dovolit i data zapisovat a sdílet mezi sebou.
V následujícím cvičení si vyzkoušíte vytvořit malou aplikaci pro nákupní seznam.
Dokumentace Firestore: https://firebase.google.com/docs/firestore
Zadání
-
Založ nový projekt pomocí create-czechitas-app.
-
Přichystej komponentu
NakupniSeznam
.- Vlož ji do stránky.
-
Přidej komponentě stav s polem objektů.
const [polozky, setPolozky] = useState([ { nazev: 'První hardcodovaná položka', }, { nazev: 'Druhá hardcodovaná položka', }, ])
-
Vypiš položky do odrážkového seznamu.
<ul> {polozky.map((polozka) => ( <li key={polozka.nazev}>{polozka.nazev}</li> ))} </ul>
- Zkontroluj v prohlížeči. Měl by se na stránce ukázat seznam o dvou položkách.
-
Ve Firebase konzoli (https://console.firebase.google.com/) přidej nový projekt. Pojmenuj ho například
Nakupni seznam
. Stiskni tlačítkoContinue
. -
V kroku
Google Analytics for your Firebase project
zruš zapnuté Analytics. Nejsou důležité a komplikují vytvoření první aplikace. -
V projektu přejdi v levém menu do záložky
Firestore
.- Stiskni tlačítko
Create database
. - Zaškrtni
Start in test mode
. - V dalším kroku pro polohu zvol
eur3 (europe-west)
.
- Stiskni tlačítko
-
Vytvoř kolekci pomocí
Start collection
s názvemseznam
.- V ní vytvoř první dokument s
Auto-ID
a s fieldemnazev
=První položka
. - Přidej druhý dokument s názvem
Druhá položka
.
- V ní vytvoř první dokument s
-
V
Project overview
přidej Web app.- Pojmenuj ji
Nakupní seznam
. - Nezaškrtávej
Firebase Hosting
. Pro hostování jsme si ukazovali Netlify (video). Není potřeba se učit nový hosting. - Register app.
- Nech si stránku otevřenou.
- Pojmenuj ji
- V terminálu ve složce s projektem z kroku 1 nainstaluj Firebase SDK pomocí
npm install firebase
. -
Ve složce
src
vytvoř soubordb.js
.- Naimportuj v něm
firebase
.import firebase from 'firebase/app' import 'firebase/firestore'
- Zkopíruj do něj proměnnou
firebaseConfig
afirebase.initializeApp(firebaseConfig)
z konzole v prohlížeči. - Exportuj konstantu pro přístup k databázi
export const db = firebase.firestore()
- Naimportuj v něm
-
Hardcodované položky nahraď za položky z db.
- Naimportuj do komponenty soubor
db.js
. -
Přidej
useEffect
, který se vykoná jen při prvním renderu.useEffect(() => {}, [])
-
V efektu poslouchej na změny v kolekci
seznam
.db.collection('seznam').onSnapshot((querySnapshot) => {})
-
Při přijetí změn (
onSnapshot
) aktualizuj stavpolozky
.setPolozky(querySnapshot.docs.map((doc) => doc.data()))
- Nastav počáteční stav na prázdné pole. Smaž hardcodované objekty.
- Naimportuj do komponenty soubor
-
Zkus ve Firebase konzoli přidat do seznamu novou položku. Měla by se ihned objevit i na tvé stránce.
-
useEffect
by si po sobě měl i uklidit pro případ, že se komponenta odpojí ze stránky.db.collection('seznam').onSnapshot
vrací funkci pro vypnutí poslouchání změn. Pokud ji vuseEffect
vrátíme, React ji ve správný čas spustí a vypne tím posluchač. Přidej před zmíněný kódreturn
.
-
Vytvoř formulář na přidávání položek.
- Přidej stav pro textové políčko
const [nazev, setNazev] = useState('')
. -
Přidej formulář.
<form> <label> Název:{' '} <input value={nazev} onChange={(event) => setNazev(event.target.value)} /> </label> <button>Přidat</button> </form>
- V události
onSubmit
zamez přenačtení stránky pomocíevent.preventDefault()
při uložení. -
V události přidej nový dokument do kolekce.
db.collection('seznam').add({ nazev })
-
Vymaž text v textovém políčku.
setNazev('')
- Přidej stav pro textové políčko
-
Seřaď položky podle data přidání.
-
Při přidávání položky do seznamu ulož i aktuální datum.
db.collection('seznam').add({ nazev, datumVytvoreni: firebase.firestore.FieldValue.serverTimestamp(), })
- Nezapomeň na
import firebase from 'firebase/app'
. -
Přidej
.orderBy('datumVytvoreni')
do dotazu na položky.useEffect(() => { return db .collection('seznam') .orderBy('datumVytvoreni') .onSnapshot((querySnapshot) => { setPolozky(querySnapshot.docs.map((doc) => doc.data())) }) }, [])
- Z výpisu ti zmizí staré položky, které datum nemají. Klidně je smaž ve Firebase konzoli.
-
-
Přidej uživateli možnost označovat položky jako koupené.
- Při přidávání položky do seznamu jí nastav
koupeno: false
. -
V mapě pro výpis položek přidej checkbox.
<input type="checkbox" checked={polozka.koupeno} onChange={(event) => {}} />
-
Při stahování položek si ulož do stavu
id
každé položky.setPolozky( querySnapshot.docs.map((doc) => { const data = doc.data() data.id = doc.id return data }), )
-
Po kliku na checkbox uprav
koupeno
v databázi.db.collection('seznam').doc(polozka.id).update({ koupeno: event.target.checked, })
- Devtools konzole ti u starých položek, které nemají vlastnost
koupeno
, bude hlásit chybu. Můžeš je pomocí Firebase konzole smazat.
- Při přidávání položky do seznamu jí nastav
-
Přidej možnost položky mazat.
- Za název položky přidej tlačítko
<button>smazat</button>
. -
Po kliku odeber položku z databáze.
db.collection('seznam').doc(polozka.id).delete()
- Za název položky přidej tlačítko
Bonus
-
Zapoj do projektu React Router.
-
Na úvodní cestě měj výpis všech položek v seznamu a na druhé detail položky.
-
Přidej switch podle ukázky. Vytvoř chybějící komponentu
Detail
, která pro zatím může vykreslovat jen nadpis<h1>Detail</h1>
.
<Switch> <Route path="/detail/:id"> <Detail /> </Route> <Route path="/"> <NakupniSeznam /> </Route> </Switch>
- Ve výpisu položek udělej ze všech názvů odkazy pomocí
<Link>
.
<Link to={`/detail/${polozka.id}`}>{polozka.nazev}</Link>
- Nezapomeň naimportovat
Link
.
import { Link } from 'react-router-dom'
-
-
Do
Detail
přidej odkaz zpět na výpis.<Link to="/">Přejí na výpis</Link>
-
Přidej do detailu výpis
id
.const { id } = useParams()
<p>Id: {id}</p>
-
Vyzkoušej si proklikat několik položek v seznamu. Sleduj, že
id
na stránce detailu se mění. -
Přidej do detailu stav pro data položky.
const [polozka, setPolozka] = useState(null)
-
Pomocí
useEffect
stáhni do stavu data.useEffect(() => { return db .collection('seznam') .doc(id) .onSnapshot((doc) => { setPolozka(doc.data()) }) }, [id])
-
Data si cvičně můžeš v detailu vypsat třeba pomocí
<pre>{JSON.stringify(polozka, null, 2)}</pre>
. -
Všimni si, že data jsou před načtením na chvilku nastaveny na
null
. To protože stahování chvilku trvá. -
Pokud se data načítají, vypiš text
Načítám
. V opačném případě do nadpisu napiš{polozka.nazev}
. -
Vypiš datum vytvoření položky.
<div> Datum vytvoření: {polozka.datumVytvoreni.toDate().toLocaleString()} </div>
Zabezpečení dat
Založená databáze v režimu test mode
se po měsíci sama uzamkne a komunikace s ní z frontendové aplikace tak přestane fungovat. Co dělat dál je popsáno zde.