Differences

This shows you the differences between two versions of the page.

Link to this comparison view

pw:laboratoare:07 [2021/04/18 14:14]
alexandru.hogea
pw:laboratoare:07 [2022/05/13 21:01] (current)
alexandru.hogea [Formulare]
Line 1: Line 1:
-====== Laboratorul 07: Introducere in ReactJS ​======+====== Laboratorul 07: Integrare Frontend-Backend ​======
  
-===== 1. Ce este Single Page Application (SPA)? ​===== +===== Scopul laboratorului ​===== 
-Un SPA sau o aplicatie ​cu o singura pagina, este o aplicatie ​(sau un website) care interactioneaza cu browserul web prin rescrierea dinamicaa DOM-ului current, cu date noi generate fie din client, fie din server. In acest caz, browserul nu este nevoit sa incarce o pagina noua.+Acest laborator reprezinta integrarea frontend-ului ​cu backend-ul creat pentru aceasta ​aplicatie. Vom introduce ​un pachet important, cel pentru axios[[https://​axios-http.com/​docs/​intro|Axios]], cu care vom putea face aceasta integrare.
  
-===== 2. Ce este JSX ? ===== +===== Ce veti invata la acest laborator? ===== 
-Considerati urmatoarea linie +Cum sa interactionati cu un server, cum sa folositi Axios pentru a face cereri si cum sa manipulam raspunsul.
-{{ :​pw:​laboratoare:​screenshot_1.png?nolink |}}+
  
-Aceasta sintaxa se numeste JSX, iar denumirea a pornit ​de la Syntax Extension to JavaScript. Aceasta sintaxa este folosita in React pentru a descrie cum va arata o componenta. JSX se poate sa va duca cu gandul la HTML, diferenta este ca JSX vine si cu toate functionalitatile JavaScript.  +===== Inainte ​de integrarea frontend-backend ===== 
-In exemplul de mai jos, declaram o variabila name, iar ulterior o folosim in interiorul JSX fiind pusa intre paranteze acolade. +==== Actualizarea formularelor ==== 
-{{ :pw:​laboratoare:​screenshot_2.png?​nolink ​|}}+<note important>​Au fost actualizate formularele astfel incat sa foloseasca biblioteca[[https://​react-hook-form.com/|react-hook-form]]. Aceasta biblioteca ne scuteste de gestionarea fiecarui input din cadrul formularelor.</​note>​
  
-De asemenea, ​puteti ​sa puneti orice cod JavaScript valid in interiorul parantezelor acolade in JSX. +Mai jos puteti ​vedea un exemplu din documentatia celor de la react-hook-formCel mai important feature este **register** care paseaza urmatoarele proprietati fiecarui input: 
-{{ :pw:​laboratoare:​screenshot_3.png?​nolink |}}+  * onChange 
 +  * name 
 +  * onBlur 
 +  * ref
  
-JSX poate sa fie folosit si in contextul unor expresiiprecum +Prin aceste proprietatise vor actualiza campurile, valorile finale fiind returnate de **getValues()**. 
-{{ :​pw:​laboratoare:​screenshot_4.png?​nolink |}}+<​code>​ 
 +import React from "​react";​ 
 +import ​useForm ​from "​react-hook-form";​
  
-Tag-urile JSX pot contine si mai multi copii. +export default function App() { 
-{{ :​pw:​laboratoare:​screenshot_5.png?​nolink |}}+  ​const ​register, handleSubmit,​ watch, formState: ​errors ​} } = useForm();​ 
 +  const onSubmit = data => console.log(data);​
  
-De asemenea, putem folosi JSX pentru a ne proteja si de eventuale atacuri. +  console.log(watch("​example"​));​ // watch input value by passing the name of it
-{{ :​pw:​laboratoare:​screenshot_6.png?​nolink |}}+
  
-**JSX reprezinta obiecte.** +  return ( 
-Babel se ocupa de compilarea JSX in apeluri React.createElement() +    /"​handleSubmit"​ will validate your inputs before invoking "​onSubmit" ​*
-{{ :pw:​laboratoare:​screenshot_7.png?nolink |}}+    <form onSubmit={handleSubmit(onSubmit)}>​ 
 +      {/register your input into the hook by invoking the "​register"​ function ​*/} 
 +      <​input defaultValue="​test"​ {...register("​example"​)} /> 
 +       
 +      ​{/* include validation with required or other standard HTML validation rules */} 
 +      <​input ​{...register("​exampleRequired",​ { requiredtrue })} /> 
 +      {/* errors will return when field validation fails  */} 
 +      {errors.exampleRequired && <​span>​This field is required</​span>​} 
 +       
 +      <input type="​submit"​ /> 
 +    </​form>​ 
 +  ); 
 +} 
 +</​code>​
  
-===== 3. Ce este React ? ===== +<​note>​Desi ​pentru ​aceasta aplicatie nu am pus mesajele ​de eroare, va recomandam sa aveti intotdeauna un raspuns pe care sa il dati utilizatorilor care nu completeaza corectGreselile facute ​de oameni in interactiunea cu un program nu sunt 'human error',​ sunt bad design.</​note>​
-React este o biblioteca JavaScript ​pentru ​construirea ​de interfete utilizatorEste creat si intretinut de Facebook si de o comunitate de dezvoltatori ( open source ) si desigur si de alte companii individuale.+
  
-===== 4. Crearea unei aplicatii React ===== +===== Ce este Axios? ​===== 
-Pentru a putea folosi tool-ul oferit de Facebook, avem nevoie ​sa indeplinim urmatoarele conditii[[https://​nodejs.org/​en/​ | Node >= 8.10 si npm >= 5.6]].+Axios este un client HTTP pentru node.js sau pentru browser. Cu ajutorul acestuia putem sa: 
 +  * interceptam cererea sau raspunsul 
 +  * transformam datele cererii sau al raspunsului 
 +  * anulam cereri 
 +  * transformam automat raspunsul pentru format JSON
  
-Pentru a genera un proiect trebuie sa rulati urmatoarele:​ 
-{{ :​pw:​laboratoare:​screenshot_8.png?​nolink |}} 
  
-Dupa rularea script-ului //npm start// puteti accesa aplicatia accesand link-ul din consola+===== Configurarile necesare ===== 
 +==== 1. Instalare Axios ====
 <​code>​ <​code>​
-http://​localhost:​3000+npm install axios
 </​code>​ </​code>​
-{{ :​pw:​laboratoare:​screenshot_9.png?nolink |}}+==== 2. Fisier de configurare rute ==== 
 +Pentru a avea toate informatiile intr-un loc, vom crea un fisier in care sa tinem toate rutele.
  
-===== 5. Componente ===== +<​note>​Daca am avea undeva hostat serverulpur si simplu am inlocui base in acest fisier, in loc sa inlocuim oriunde folosim axios.</note> 
-Componentele va permit sa va impartiti interfata utilizator in "​piese"​ reutilizabileiar in acelasi timp va puteti gandi la fiecare piesa ca fiind izolata. +<​note>​Am grupat rutele ​in functie ​de functionalitativa recomandam ​sa tineti informatiile statice sub forma cat mai ordonata.</​note>​
- +
-Conceptual, componentele sunt asemanatoare cu functiile JavaScript. Acestea accepta intrari (denumite "​props"​) ​si returneaza elemente React, care descriu ceea ce ar trebui sa apara in interfata. +
- +
-==== 5.1. Functional Components ==== +
-Cea mai simpla cale de a defini o componenta este aceea de a scrie o functie JavaScript +
-{{ :​pw:​laboratoare:​screenshot_10.png?​nolink |}} +
- +
-Aceasta functie este o componenta valida React deoarece accepta un singur obiect "​props"​ (proprietati) cu date si returneaza un element React. Aceste componente poarta denumirea de **function components** deoarece ele reprezinta niste functii JavaScript. +
- +
-==== 5.2. Class Components ==== +
-De asemeneaputeti folosi si o [[https://​developer.mozilla.org/​en-US/​docs/​Web/​JavaScript/​Reference/​Classes | clasa ES6]] pentru a defini o componenta:​ +
-{{ :​pw:​laboratoare:​screenshot_11.png?​nolink |}} +
- +
-Cele doua componente definite mai sus, sunt echivalente din punct de vedere React. +
- +
-==== 5.3 Adaugarea unei componente ​in DOM (Rendering a Component) ==== +
-Pana acum, am intampinat elemente React care reprezentau tag-uri DOM, precum: +
-{{ :​pw:​laboratoare:​screenshot_12.png?nolink |}} +
- +
-De asemenea, elementele pot reprezenta si componente definite de utilizator:​ +
-{{ :​pw:​laboratoare:​screenshot_13.png?​nolink |}} +
- +
-Cand React descopera un element care reprezinta o componenta definita de utilizator, acesta trimite atributele JSX si copiii catre aceasta componenta folosind un singur obiect. Acest obiect poarta numele de "​props"​. +
- +
-In exemplul urmator, codul "​randeaza",​ in pagina, mesajul ​//Hello, Sara//. +
-{{ :​pw:​laboratoare:​screenshot_14.png?​nolink |}} +
- +
-Componentele create pot fi reutilizate de cate ori dorim. Spre exemplu, putem crea o componenta //App// care afiseaza //Welcome// de mai multe ori, folosind alt nume. +
-{{ :​pw:​laboratoare:​screenshot_15.png?​nolink |}} +
- +
-==== 5.4 Stare ( State ) ==== +
-[[https://​reactjs.org/​docs/​state-and-lifecycle.html | State]] reprezinta un obiect JavaScript care pastreaza informatia influentand aspectul sau starea componentei compilate si randate. Diferenta fata de **props** este aceea ca starea este mentinuta ​in contextul componentei - similar cu definirea unei variabile in interioriul unei functii. +
- +
- +
-=== 5.4.1 Functional Components === +
-In cazul componentelor functionale,​ o variabila ​de stare este declarata cu ajutorul useState ([[https://​reactjs.org/​docs/​hooks-state.html |React Hooks]]). O variabila de stare poate lua mai multe forme: stringnumar sau obiect. Functia useState primeste ca paramentru valoarea initiala pe care vrem sa o atribuim variabilei si returneaza variabila de stare impreuna cu functia de actualizare,​ similara cu this.setState din componentele de tip clasa. +
- +
-{{ :​pw:​laboratoare:​state_functional.png?​nolink&​700 |}} +
- +
-=== 5.4.2 Class Components === +
-{{ :​pw:​laboratoare:​state_class.png?​nolink&​700 |}} +
- +
-Cele doua componente prezentate ​mai sus sunt echivalente,​ insa exista o mica diferenta:​ +
- +
-Class Components fac referire la state sau props folosind **this**.+
 <​code>​ <​code>​
-Class components+const base = "​https://​localhost:​7002/​api/​v1/";​ 
 +const routes = { 
 +    books: { 
 +        addBook: "​Books/​addBook",​ 
 +        getAll: "​Books/​viewAllBooks",​ 
 +        getBook: (id) => `Books/​viewStatusAboutBook/​${id}`,​ 
 +        deleteBook: (id) => `Books/​deleteBook/​${id}`,​ 
 +    }, 
 +    metrics: { 
 +        getBook: (id) => `Metrics/​metricsAboutBook/​${id}`,​ 
 +    }, 
 +    rentals: { 
 +        rentBook: "​Rentals/​rentBook",​ 
 +        myRentals: "​Rentals/​viewMyRentals",​ 
 +        returnBook: (id) => `Rentals/​returnBook/​${id}`,​ 
 +    }, 
 +    profile: { 
 +        setupProfile:​ "​Profiles/​registerProfile",​ 
 +        getProfile: "​Profiles/​viewProfile",​ 
 +    }, 
 +};
  
-this.state +export { base, routes };
-this.props+
 </​code>​ </​code>​
 +==== 3. Configurare instanta Axios ==== 
 +De ce o [[https://​axios-http.com/​docs/​instance|instanta]] de Axios? Pentru ca in diferite cazuri avem nevoie de o configurare mai specifica pentru interactiunea cu backend-ul. De asemenea, aceasta instanta ne ajuta pentru a folosi [[https://​axios-http.com/​docs/​interceptors|interceptori]].  
 +<note tip> 
 +Interceptorii ne pot ajuta in 2 moduri: 
 +  - Daca vrem sa modificam orice cerere inainte sa o trimitem (ex: sa atasam un header in plus) 
 +  - Daca vrem sa gestionam datele primite de la server 
 +</​note>​ 
 +In cazul nostru, nu a trebuit sa folosim interceptori.
 <​code>​ <​code>​
-Functional Components+import axios from "​axios";​ 
 +import { base } from "​./​Api";​
  
-state +const axiosInstance = axios.create({ 
-props +    ​baseURL:​ base, 
-</​code>​+    ​timeout:​ 1000, 
 +});
  
-==== 5.5 Event Handling ==== +export default axiosInstance;​
-Gestionarea evenimentelor cu elemente React este foarte asemanatoare cu gestionarea evenimentelor pe elemente DOM. Totusi, exista cateva ​ diferente de sintaxa: +
-  * evenimentele din React sunt camelCase +
-  * pentru gestionarea evenimentelor in React sunt folosite functii, nu string-uri +
- +
-HTML +
-{{ :​pw:​laboratoare:​screenshot_16.png?​nolink |}} +
- +
- +
-React +
-{{ :​pw:​laboratoare:​screenshot_17.png?​nolink |}} +
- +
-HTML +
-{{ :​pw:​laboratoare:​screenshot_19.png?​nolink |}} +
- +
-React +
-{{ :​pw:​laboratoare:​screenshot_18.png?​nolink |}} +
- +
-==== 5.6 Conditional Render ==== +
-Randarea bazata pe conditii, in React, functioneaza in acelasi mod precum conditionarea in JavaScript. Folositi operatori JavaScript precum [[https://​developer.mozilla.org/​en-US/​docs/​Web/​JavaScript/​Reference/​Statements/​if...else |if]] sau [[https://​developer.mozilla.org/​en-US/​docs/​Web/​JavaScript/​Reference/​Operators/​Conditional_Operator |conditional operator]] pentru a crea elemente reprezentand starea curenta. +
- +
-Considerati urmatoarele doua componente:​ +
-{{ :​pw:​laboratoare:​screenshot_20.png?​nolink |}} +
- +
-Vom implementa o componenta //​Greeting//​ care afiseaza una dintre aceste componente, daca un utilizator este autentificat sau nu. +
-{{ :​pw:​laboratoare:​screenshot_21.png?​nolink |}} +
- +
-==== 5.7 Liste si chei (key) ==== +
-In primul rand, sa ne amintim cum transformam listele in JavaScript. +
-{{ :​pw:​laboratoare:​screenshot_22.png?​nolink |}} +
- +
-Acest cod afiseaza urmatorul rezultat in consola +
-<​code>​ +
-[2, 4, 6, 8, 10]+
 </​code>​ </​code>​
 +==== 4. Folosirea instantei pentru a face cereri ====
 +<​note>​Cele mai folosite tipuri de cereri folosite sunt: GET, POST, PUT si DELETE. GET este folosit pentru a cere resurse, POST pentru crearea unei resurse, PUT pentru actualizarea unei resurse deja existente, iar DELETE, precum ii zice si numele, va sterge o resursa.</​note>​
 +Mai jos puteti gasi doua exemple de functii care fac doua cereri: una de tip GET - pentru a cere toate cartile si una de tip POST - pentru a adauga o carte. Primul pas in ambele este de a prelua **access token-ul** provenit de la auth0. Aceasta actiune o facem folosind functia getAccessTokenSilently() pe care auth0 ne-o ofera. Al doilea pas este sa folosim instanta noastra de axios pentru a cere datele respective sau pentru a adauga resursa. In final, pentru a citi raspunsul cererii, vom folosi **then** pentru a actualiza lista de carti.
  
-=== Afisarea mai multor componente ===+<note tip>​Pentru '​prinderea'​ erorilor puteti folosi **catch**. </​note>​
 <​code>​ <​code>​
-const numbers ​[1234, 5]; +  ​const getAllBooks ​useCallback(async () => { 
-const listItems = numbers.map((number) => +    const accessToken = await getAccessTokenSilently();​ 
-  ​<​li>​{number}</​li>​ +    axiosInstance 
-); +      .get(routes.books.getAll
-</​code>​+        headers: { 
 +          Authorization:​ `Bearer ${accessToken}`, 
 +        }
 +      }) 
 +      ​.then(({ data }) => setBooks(data));​ 
 +  }, [getAccessTokenSilently]);
  
-{{ :​pw:​laboratoare:​screenshot_23.png?​nolink |}} +  const handleAddBook = (form) => { 
- +    (async () => 
-Cand rulam acest cod, in consola va fi afisat un mesaj de atentionare spunandu-ne ca pentru fiecare //​li// ​(list itemtrebuie sa furnizam o cheie unica+      const accessToken = await getAccessTokenSilently()
-{:pw:​laboratoare:​screenshot_24.png?​nolink |}} +      axiosInstance 
- +        .post(routes.books.addBook,​ form, { 
-Pentru a rezolva aceasta problematrebuie sa introducem urmatoarea modificare: +          ​headers: ​{ 
-{{ :​pw:​laboratoare:​screenshot_25.png?​nolink |}+            Authorization`Bearer ${accessToken}`, 
- +          ​}, 
-Aceste **key**s ​(cheiajuta React-ul la identificarea elementelor care s-au schimbat, adaugat si eliminat. Putem privi aceste chei precum identitatea unui element. +        }) 
- +        ​.then(() => getAllBooks());​ 
-==== 5.8 Compozitie ==== +    })(); 
-React are un model puternic de compozitie si va recomandam sa folositi compozitia in loc de mostenire pentru a reutiliza codul intre componente +  };
- +
-Unele componente nu stiu din timp ce copii vor avea. Aceste componente sunt de obicei folosite cand ne definini **Layout**-ul aplicatiei sau orice element care reprezinta o '​cutie'​ pentru elementele noastre. +
- +
-Fiecare componenta React, are o proprietare rezervata in obiectul **props** numita **children**. Aceasta proprietate poate fi accesata in felul urmator: +
- +
-<code+
-Class components +
- +
-this.props.children+
 </​code>​ </​code>​
  
 +<note tip>Daca vrem sa primim toate cartile de fiecare data cand componenta noastra Books se va randa, atunci vom folosi **useEffect**.</​note>​
 <​code>​ <​code>​
-Functional components +  useEffect(() => { 
- +    ​getAllBooks();​ 
-props.children+  }, [getAllBooks]);​
 </​code>​ </​code>​
  
-{{ :​pw:​laboratoare:​screenshot_26.png?​nolink |}} +Un exemplu ​de cerere de tip DELETE o avem pentru stergerea ​unei resurse ​(carti):
-{{ :​pw:​laboratoare:​screenshot_27.png?​nolink |}} +
- +
- +
-===== 6. Sass (Syntactically Awesome Style Sheets) ===== +
- +
-==== 6.1 Ce este Sass si de ce este util? ==== +
- +
-Stilizarea ​unei pagini web poate sa devina obositoare scriind aceleasi linii de cod (culori, layout, font, pozitie), mai ales cand vrem sa schimbam tema.[[https://​sass-lang.com/​guide|Sass]],​ pre-procesor CSS, vine in ajutorul nostru, oferindu-ne posibilitatea folosirii de variabile, mixins sau nesting. +
- +
-==== 6.2 Variabile, functii, nesting ==== +
 <​code>​ <​code>​
-SCSS SYNTAX +  const handleDelete = () => { 
-$font-stack: ​   Helvetica, sans-serif; +    ​**confirmare stergere resursa** 
-$primary-color:​ #333; +    ​axiosInstance 
- +      ​.delete(routes.books.deleteBook(id)) 
-body { +      ​.then(() => navigate("/​books"​))
-  font: 100% $font-stack+  ​};
-  ​color: $primary-color; +
-}+
 </​code>​ </​code>​
  
----- +<note tip>​Inainte de stergerea resursei, utilizatorul ar trebui cumva anuntat de actiunea acestuia, in caz ca a apasat din greseala. Acest lucru se poate face printr-un pop-up in care sa confirme stergerea.</​note>​ 
- +Putem observa ca functia este asemanatoare,​ avem instanta ​de axios care va face o cerere ​de tip **delete** ​si daca cererea a fost efectuata cu successe va naviga pe pagina cu toate cartile.
-===== Exercitii ===== +
-{{ :​pw:​laboratoare:​lab_2_-_counter_-_width.png?​nolink&​750 |}} +
-{{ :​pw:​laboratoare:​lab2_-_brief.png?​nolink&​750 |}} +
- +
-Realizati urmatoarele exercitii astfel incat sa respecte design-ul ​de mai sus. Informatiile legate ​de font si culori le puteti gasi sub design. Pentru fontputeti folosi [[https://​fonts.google.com|Google Fonts]], iar pentru partea de layout folositi [[https://​flexboxfroggy.com|Flexbox]].+
  
-  - Generati o aplicatie React folosind **create-react-app**. 
-  - Creati o componenta **Counter** care sa afiseze un numar si 3 butoane **Increment**,​ **Decrement** si **Reset**. 
-  - Adaugati functionalitatea necesara pentru a incrementa, decrementa si reseta starea componentei **Counter**. 
-  - Creati 3 componente (Class sau Functional) **Header**, **Footer** si **Layout**. 
-  - Creati o sectiune in componenta **Layout** care sa reprezinte continutul afisat pe pagina, iar in interiorul acestui continut sa putem adauga copii folosind compozitia. 
-  - Adaugati **Header** si **Footer** in Layout pentru a defini structura paginii. 
-  - Afisati componenta **Counter** in **Layout**ul pe care l-ati creat anterior. 
pw/laboratoare/07.1618744464.txt.gz · Last modified: 2021/04/18 14:14 by alexandru.hogea
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0