This shows you the differences between two versions of the page.
pw:laboratoare:09 [2020/04/16 10:14] alexandru.hogea [Exercitii] |
pw:laboratoare:09 [2021/05/09 19:53] (current) alexandru.hogea [Exercitii] |
||
---|---|---|---|
Line 1: | Line 1: | ||
- | ===== Laboratorul 09: SASS & React Hooks ===== | + | ===== Laboratorul 09: React Router & Request-uri HTTP ===== |
- | ==== 1. Syntactically Awesome Style Sheets ==== | + | ===== Premisa ===== |
+ | <note important>In cadrul acestui laborator, vom accesa backend-ul creat la [[https://gitlab.com/tehnologiiweb/lab5| Laboratorul 5]]. Cel mai recomandat este sa il clonati din nou si sa dati docker-compose up. Atat serverul cat si baza de date ruleaza amandoua in Docker.</note> | ||
- | SASS este un preprocesor de stil compilat in CSS. Va permite sa utilizati variabile, nested rules, mixins, functii si multe altele, toate cu o sintaxa complet compatibila CSS. SASS ajuta la mentinerea bine organizata a fisierelor mari de stil si faciliteaza partajarea designului in cadrul proiectelor. | + | ===== 1. React Router ===== |
+ | React Router DOM este un API creat pentru React pentru a "simula" un browser history pentru aplicatia noastra. Deoarece aplicatia noastra este un Single Page Application (SPA), browser-ul nostru nu navigheaza prin fisiere html. | ||
- | === 1.1 Variabile === | + | ==== 1.1. Instalare React Router ==== |
+ | Pentru a instala react-router-dom trebuie sa executam urmatoarea comanda: | ||
+ | <code>npm install react-router-dom</code> | ||
- | Ganditi-va la variabile ca la o modalitate de a stoca informatiile pe care doriti sa le reutilizati in intreaga aplicatie (stiluri). Puteti stoca lucruri precum culori, stive de fonturi sau orice valoare CSS pe care considerati ca veti dori sa o reutilizati. SASS foloseste simbolul **$** pentru a face ceva variabil. Mai jos puteti vedea un exemplu: | + | ==== 1.2. Utilizarea React Router ==== |
+ | Utilizarea React Router-ului se realizeaza in 3 pasi: | ||
+ | * Adaugarea dependintelor din react-router-dom (**HashRouter**, **Switch** si **Route**) | ||
- | {{ :pw:laboratoare:sass_1.png?nolink |}} | + | {{ :pw:laboratoare:router-1.png?nolink&500 |}} |
- | === 1.2 Nested rules (Ierarhizare) === | + | * Inglobarea tuturor componentelor din cadrul aplicatiei in **<HashRouter>** si **<Switch>** |
+ | * Definirea rutelor folosind **<Route>** | ||
- | Cand scrieti HTML, ati observat probabil ca are o ierarhizare clara si vizuala. CSS, in schimb, nu. | + | {{ :pw:laboratoare:router-2.png?nolink&500 |}} |
- | SASS va permite sa va ierarhizati selectoarele CSS intr-un mod care sa urmeze aceeasi ierarhie vizuala a HTML-ului. Fiti constienti de facptul ca regulile exagerat de imbibate vor duce la CSS supra-calificate, care s-ar putea dovedi greu de intretinut si nu este, in general, considerata o practica buna. | + | |
- | {{ :pw:laboratoare:sass_2.png?nolink |}} | + | Schimbarea continutului dinamic se realizeaza prin folosirea componentei **<Link>** din react-router-dom |
- | === 1.3 Mixins === | + | {{ :pw:laboratoare:router-3.png?nolink&400 |}} |
- | Unele lucruri din CSS sunt destul de complicate de scris, in special cu CSS3 si cu numeroasele prefixuri ale furnizorilor care exista. Un mixin va permite sa faceti grupuri de declaratii CSS pe care doriti sa le reutilizati pe site-ul vostru. | + | ===== 2. Axios si Request-uri HTTP ===== |
+ | Axios este o biblioteca JavaScript folosita pentru a face **Request-uri HTTP** din **Node.Js** sau **XMLHttpRequest** din browser, cerinta principala fiind compatibilitatea cu **ES6 Promise API**. | ||
- | {{ :pw:laboratoare:sass_3.png?nolink |}} | + | === 2.1. Caracteristici principale === |
+ | * **[[https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest|XMLHttpRequests]]** din browser | ||
+ | * Request-uri **[[https://nodejs.org/api/http.html|HTTP]]** din **Node.JS** | ||
+ | * Suporta **[[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise|Promise API]]** | ||
+ | * Interceptare request-uri si responses | ||
+ | === 2.2. Instalare axios === | ||
- | ===== 2. React Hooks ===== | + | <code>npm install axios</code> |
- | **[[https://reactjs.org/docs/hooks-overview.html|Hooks]]** sunt o noua adaugare in **React 16.8**. Va permit sa utilizati functiile de stare si alte functii React, fara a scrie o clasa. Avantajul este mai putin cod scris pentru a obtine aceeasi functionalitate. | + | |
- | === 2.1 useState() === | ||
- | [[https://reactjs.org/docs/hooks-state.html|useState]] este un hook de React care va permite sa interactionati cu starea unei componente. Acesta va intoarce un vector format din 2 elemente: | ||
- | * Variabila de stare | ||
- | * Functia care va modifica variabila de stare | ||
- | Functia **useState** primeste ca parametru valoarea initiala a starii | + | === 2.3. HTTP Get === |
- | <code javascript> | + | {{ :pw:laboratoare:axios_get.png?nolink&500 |}} |
- | const [myState, myFunctionToChangeState] = useState(initialValue); | + | |
- | </code> | + | |
- | <note tip>Atentie, valoarea initiala trebuie sa reflecte tipul de stare pe care vreti sa il retineti (string, numar, obiect, etc...)</note> | + | === 2.4. HTTP Post === |
- | <note tip>O componenta poate apela **useState** de mai multe ori, pentru a retine stari diferite</note> | + | {{ :pw:laboratoare:axios_post.png?nolink&500 |}} |
- | {{:pw:laboratoare:mai_multe_stari.png?800|}} | + | === 2.5. HTTP Put === |
+ | {{ :pw:laboratoare:axios_put.png?nolink&500 |}} | ||
- | Acest exemplu reda un contor. Cand faceti clic pe buton, creste valoarea: | + | === 2.6. HTTP Delete === |
+ | {{ :pw:laboratoare:axios_delete.png?nolink&500 |}} | ||
- | {{ :pw:laboratoare:usestate_1.png?nolink |}} | + | === 2.7. HTTP Request cu Headers === |
+ | {{ :pw:laboratoare:axios_headers.png?nolink&500 |}} | ||
- | <note tip>Observati cum valoarea initiala a starii este 0</note> | ||
- | === 2.2 useEffect() === | + | <note important>Pe langa HOST (localhost in cazurile de mai sus), trebuie mentionat si portul si protocolul. Pentru acest laborator o sa fie http://localhost:3000</note> |
- | [[https://reactjs.org/docs/hooks-effect.html|useEffect]] este al doilea hook important din React si va permite propagarea **efectelor colaterale** din React - sau pe scurt, **efecte** - (de exemplu, modificarea DOM-ului, afisarea unor alerte, preluarea unor date, etc...). | + | ===== Exercitii ===== |
- | Orice actiune care nu se poate efectua in timpul randarii (render), pentru ca poate modifica structura componentei, este considerat efect. | + | {{ :pw:laboratoare:brief.png?nolink&700 |}} |
- | Pe vremuri, cand componentele functionale nu erau atat de folosite si inca se foloseau foarte mult componentele clasa, aceste efecte erau tratate in **ciclurile de viata** ale componentelor. Aceste cicluri de viata nu sunt nimic mai mult decat metode ale claselor de React. Amintim cateva: | + | {{ :pw:laboratoare:lab_4_-_register.png?nolink&700 |}} |
- | * **componentDidMount** - metoda care se executa dupa redarea initiala a componentei | + | |
- | * **componentDidUpdate** - metoda care se executa dupa ce state sau props au fost modificate | + | |
- | * **componentWillUnmount** - metoda care se executa inainte de stergerea componentei - adica este scoasa din DOM | + | |
- | In principal, **efectele** declarate folosind **useEffect** se realizeaza, prin analogie, in **componentDidMount**, **componentDidUpdate** si, daca este declarat un comportament specific si in **componentWillUnmount**. | + | {{ :pw:laboratoare:lab_4_-_login.png?nolink&700 |}} |
- | Mai jos aveti un exemplu de efect care schimba titlul paginii: | + | {{ :pw:laboratoare:lab_4_-_books.png?nolink&700 |}} |
- | {{ :pw:laboratoare:useeffect_1.png?nolink |}} | + | {{ :pw:laboratoare:lab_4_-_authors.png?nolink&700 |}} |
- | Prin analogie, asa s-ar fi scris folosind clase: | + | <note tip>Pentru vizualizarea detaliilor, puteti intra pe acest [[https://xd.adobe.com/view/7ba0a1d7-2e62-45d7-b27b-f74a16e55876-2ef3/screen/47f00dd6-0679-4cbb-b4ae-abe03f8445fc/specs/|link]] si alegand optiunea **</>** din meniul vertical aflat in dreapta.</note> |
- | {{:pw:laboratoare:react_hook_clasa.png|}} | + | <note tip>Pentru ilustratie puteti folosi [[https://undraw.co|Undraw]]. Ilustratia folosita in design poate fi gasita cautand 'Tree swing'.</note> |
- | <note tip> Observati cum logica este duplicata in **componentDidMount** si **componentDidUpdate**. useEffect elimina aceasta duplicare</note> | + | 1. Creati o componenta **Autentificare** care sa contina un formular cu **doua campuri text si un buton de Submit** respectiv **Register**. |
- | + | <note important>Componenta Autentificare va fi responsabila de a trimite un request de tip POST catre API, avand in body datele necesare autentificarii respectiv inregistrarii utilizatorului. | |
- | Exista cazuri cand doriti sa anulati un efect in momentul in care nu mai aveti nevoie de componenta sau cand proprietatile componentei se schimba. Acest proces se numeste **curatare**. In Reactul clasic, acest lucru era scris in metoda **componentWillUnmount**, sau in metoda **componentDidUpdate**. Pentru a face acest lucru in useEffect, este nevoie sa **returnati o functie**. | + | |
- | + | ||
- | Asadar, ce se intampla in corpul functiei useEffect se intampla **de fiecare data** cand componenta se randeaza (render) si ce se returneaza se executa **de fiecare data** cand componenta a terminat de executat render. | + | |
- | + | ||
- | De exemplu, sa presupunem ca avem un API de Chat care are doua metode: subscribe si unsubscribe. Aceste doua metode au doi parametri, un id si o functie de callback care seteaza statusul pe online sau offline. Ne dorim sa dam subscribe la inceputul componentei si sa dam unsubscribe, atunci cand parasim componenenta. | + | |
- | + | ||
- | Folosind useEffect, acest lucru se poate realiza foarte usor: | + | |
- | + | ||
- | {{ :pw:laboratoare:useeffect_2.png?nolink |}} | + | |
- | + | ||
- | Pe de alta parte, folosind clasa, codul ar fi aratat astfel: | + | |
- | + | ||
- | {{:pw:laboratoare:react_hook_clasa_2.png|}} | + | |
- | + | ||
- | <note tip>Observati cum ce este returnat in **useEffect** este scris in **componentWillUnmount** si ce este scris in corpul **useEffect** este scris in **componentDidMount**, asa cum am explicat anterior.</note> | + | |
- | + | ||
- | <note important>Codul din ultima coza este un cod ce are bug. Ganditi-va la urmatorul caz: cand **props** este modificat (adica atunci cand parintele ii trimite alta valoare pentru props), componenta **NU** va efectua unsubscribe, chiar daca id-ul s-a modificat. Acest lucru trebuie tratat tot in **componentDidMount**. useEffect elimina aceasta problema, executand codul la fiecare render.</note> | + | |
- | + | ||
- | Asa ar fi trebuit sa arate codul corect, folosind clase: | + | |
- | + | ||
- | {{:pw:laboratoare:react_hook_clasa_3.png|}} | + | |
- | ==== Exercitii ==== | + | |
- | + | ||
- | Vom extinde aplicatia creata la laboratorul precedent. | + | |
- | + | ||
- | 1. Folosind componentele App si Count, trimiteti valoarea counter-ului si functiile (incrementare, decrementare, reset) folosind props. Cand counter-ul ajunge 0, afisati o alerta. | + | |
- | <note important>Componenta **Count** si **App** trebuie sa fie componente functionale. Pentru afisarea alertei va trebui sa folositi **useEffect()**. Valoarea lui count va fi definita drept state in App, la fel si functiile de incrementare, decrementare si reset.</note> | + | |
- | + | ||
- | 2. Instalati biblioteca **node-sass**. hint: **npm** | + | |
- | + | ||
- | 3. Modificati fisierele de css din extensia **.css** in **.scss**. | + | |
- | <note important> | + | |
- | De asemenea, React permite modularizarea fisierelor SCSS prin denumirea acestora in **numeFisier.module.scss**. | + | |
- | In acest caz, importarea si referentierea claselor css, se face in felul urmator: | + | |
<code> | <code> | ||
- | numeFisier.module.scss | + | { |
- | + | username: "admin", | |
- | .container { | + | password: "admin" |
- | display: flex; | + | |
- | justify-content: space-between; | + | |
- | align-items: center; | + | |
- | flex-direction: row; | + | |
- | padding: 1rem 0; | + | |
- | font-size: 1em; | + | |
- | font-weight: 700; | + | |
- | [...] | + | |
} | } | ||
+ | </code> | ||
- | import styles from './numeFisier.module.scss'; | + | Raspunsul primit de la server, in cazul login, va contine token-ul JWT. Stocarea token-ului se face in browser, folosind **localStorage**. |
- | <div className={styles.container}> | + | Stocare token in **localStorage** |
- | [...] | + | <code> |
- | </div> | + | localStorage.setItem("token", jwt_token); |
</code> | </code> | ||
- | In cazul in care doriti import-ul standard, fara module, acesta va arata in felul urmator: | + | Citirea token-ului din **localStorage** |
- | + | ||
- | numeFisier.scss | + | |
<code> | <code> | ||
- | .container { | + | localStorage.getItem("token") |
- | display: flex; | + | </code> |
- | justify-content: space-between; | + | </note> |
- | align-items: center; | + | |
- | flex-direction: row; | + | |
- | padding: 1rem 0; | + | |
- | font-size: 1em; | + | |
- | font-weight: 700; | + | |
- | [...] | + | |
- | } | + | |
- | import './numeFisier.scss'; | + | 2. Creati doua componente, **Book** si **Author**, care sa afiseze detaliile despre fiecare carte, respectiv autor. Stilizarea poate sa urmeze design-ul de mai sus. Nu este obligatorie copierea exacta a design-ului, importanta este afisarea datelor. |
- | <div className="container"> | + | 3. Creati o componenta **BooksList** care sa contina o lista cu toate cartile existente, respectiv **AuthorsList** care sa contina o lista cu toti autorii existenti in baza de date. Pentru afisarea tuturor cartilor, respectiv autorilor, se vor folosi componentele create anterior, **Book** si **Author**. Aceste componente pot fi reprezentate de paginile Books si Authors din design. Din nou, nu este obligatorie respectarea design-ului. |
- | [...] | + | |
- | </div> | + | |
- | </code> | + | |
- | </note> | + | 4. Componentele **BooksList** si **AuthorsList** trebuie sa trimita cate un request de HTTP Get pentru a aduce toate intrarile din baza de date. |
- | 4. Stilizarea **Header**, **Nav** si **Footer**. | + | <note important>Cererile catre server pot fi date fie la apasarea pe un buton, fie atunci cand se incarca componenta (hint, useEffect)</note> |
- | * Nav: va prezenta in partea din stanga un logo si 3 meniuri (**Home, Books, Authors**) iar in partea din dreapta, un meniu de tip Dropdown cu un buton de **Logout** | ||
- | * Header: va afisa ca background o imagine (la libera alegere) | ||
- | * Footer: poate avea orice culoare, iar in Footer se va afisa Prenumle si Numele studentului, facultatea si anul absolvirii. | ||
- | 5. Componenta Layout va trebui sa alcatuiasca toata interfata utilizator, folosind **Header**, **Nav** si **Footer**. | ||
- | |