Differences

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

Link to this comparison view

pw:laboratoare:07 [2021/04/18 14:29]
alexandru.hogea [6.4 Extend]
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 campurilevalorile finale fiind returnate ​de **getValues()**.
-{{ :​pw:​laboratoare:​screenshot_4.png?​nolink |}} +
- +
-Tag-urile JSX pot contine si mai multi copii. +
-{{ :​pw:​laboratoare:​screenshot_5.png?​nolink |}} +
- +
-De asemeneaputem folosi JSX pentru a ne proteja si de eventuale atacuri. +
-{{ :​pw:​laboratoare:​screenshot_6.png?​nolink |}} +
- +
-**JSX reprezinta obiecte.** +
-Babel se ocupa de compilarea JSX in apeluri React.createElement() +
-{{ :​pw:​laboratoare:​screenshot_7.png?​nolink |}} +
- +
-===== 3. Ce este React ? ===== +
-React este o biblioteca JavaScript pentru construirea de interfete utilizator. Este 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 ===== +
-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]]. +
- +
-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+
 <​code>​ <​code>​
-http://​localhost:​3000 +import React from "​react";​ 
-</​code>​ +import ​useForm ​from "​react-hook-form";​
-{{ :​pw:​laboratoare:​screenshot_9.png?​nolink |}}+
  
-===== 5. Componente ===== +export default function App() { 
-Componentele va permit sa va impartiti interfata utilizator in "​piese"​ reutilizabile,​ iar in acelasi timp va puteti gandi la fiecare piesa ca fiind izolata.+  const { register, handleSubmit,​ watch, formState: { errors } } useForm();​ 
 +  const onSubmit ​data => console.log(data);
  
-Conceptual, componentele sunt asemanatoare cu functiile JavaScriptAcestea accepta intrari ​(denumite ​"props"​) ​si returneaza elemente React, care descriu ceea ce ar trebui sa apara in interfata.+  console.log(watch("example")); // watch input value by passing the name of it
  
-==== 5.1. Functional Components ==== +  return ( 
-Cea mai simpla cale de a defini o componenta este aceea de a scrie o functie JavaScript +    /* "​handleSubmit"​ will validate your inputs before invoking "​onSubmit"​ */ 
-{{ :​pw:​laboratoare:​screenshot_10.png?​nolink |}+    <​form onSubmit={handleSubmit(onSubmit)}> 
- +      {/* register your input into the hook by invoking the "register" function */} 
-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. +      <​input defaultValue="​test" ​{...register("​example"​)} /> 
- +       
-==== 5.2. Class Components ==== +      {/* include validation with required or other standard HTML validation rules */
-De asemenea, puteti folosi si o [[https://​developer.mozilla.org/​en-US/​docs/​Web/​JavaScript/​Reference/​Classes | clasa ES6]] pentru a defini o componenta:​ +      <​input ​{...register("exampleRequired", { requiredtrue })} /> 
-{{ :​pw:​laboratoare:​screenshot_11.png?nolink |}} +      {/* errors will return when field validation fails  ​*/} 
- +      {errors.exampleRequired ​&& <​span>​This field is required</​span>​
-Cele doua componente definite mai sus, sunt echivalente din punct de vedere React. +       
- +      <​input type="​submit"​ /> 
-==== 5.3 Adaugarea unei componente in DOM (Rendering a Component==== +    </form
-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 obiectAcest 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: string, numar 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+
-Class components +
- +
-this.state +
-this.props+
 </​code>​ </​code>​
  
-<code> +<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 corect. Greselile facute de oameni in interactiunea cu un program nu sunt 'human error',​ sunt bad design.</​note>
-Functional Components+
  
-state +===== Ce este Axios? ===== 
-props +Axios este un client HTTP pentru node.js sau pentru ​browserCu ajutorul acestuia putem sa
-</​code>​ +  * interceptam cererea sau raspunsul 
- +  * transformam datele cererii ​sau al raspunsului 
-==== 5.5 Event Handling ​==== +  * anulam cereri 
-Gestionarea evenimentelor cu elemente React este foarte asemanatoare cu gestionarea evenimentelor pe elemente DOM. Totusi, exista cateva ​ diferente de sintaxa: +  * transformam automat raspunsul pentru format JSON
-  * 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+===== Configurarile necesare ===== 
 +==== 1. Instalare Axios ====
 <​code>​ <​code>​
-[2, 4, 6, 8, 10]+npm install axios
 </​code>​ </​code>​
 +==== 2. Fisier de configurare rute ====
 +Pentru a avea toate informatiile intr-un loc, vom crea un fisier in care sa tinem toate rutele.
  
-=== Afisarea ​mai multor componente ===+<​note>​Daca am avea undeva hostat serverul, pur si simplu am inlocui base in acest fisier, in loc sa inlocuim oriunde folosim axios.</​note>​ 
 +<​note>​Am grupat rutele in functie de functionalitati,​ va recomandam sa tineti informatiile statice sub o forma cat mai ordonata.</​note>​
 <​code>​ <​code>​
-const numbers ​[1, 2, 3, 4, 5]+const base "​https://​localhost:​7002/​api/​v1/"​
-const listItems ​numbers.map((number) => +const routes ​
-  <​li>{number}</li> +    books: { 
-); +        addBook: "​Books/​addBook",​ 
-</code>+        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",​ 
 +    }, 
 +};
  
-{{ :​pw:​laboratoare:​screenshot_23.png?​nolink |}} +export ​baseroutes ​};
- +
-Cand rulam acest codin consola va fi afisat un mesaj de atentionare spunandu-ne ca pentru fiecare //li// (list item) trebuie sa furnizam o cheie unica. +
-{{ :​pw:​laboratoare:​screenshot_24.png?​nolink |}+
- +
-Pentru a rezolva aceasta problema, trebuie sa introducem urmatoarea modificare:​ +
-{{ :​pw:​laboratoare:​screenshot_25.png?​nolink |}} +
- +
-Aceste **key**s (chei) ajuta React-ul la identificarea elementelor care s-au schimbat, adaugat si eliminat. Putem privi aceste chei precum identitatea unui element. +
- +
-==== 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>​
 +==== 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";​
  
-props.children +const axiosInstance = axios.create({ 
-</​code>​+    ​baseURL:​ base, 
 +    timeout: 1000, 
 +});
  
-{{ :​pw:​laboratoare:​screenshot_26.png?​nolink |}} +export default axiosInstance;
-{{ :​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, mixins, nesting ==== +
-**Exemplu folosire variabile** +
- +
-<​code>​ +
-$font-stack: ​   Helvetica, sans-serif; +
-$primary-color:​ #333; +
- +
-body { +
-  font: 100% $font-stack;​ +
-  color: $primary-color;​ +
-}+
 </​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.
  
-**Exemplu folosire nesting** +<note tip>​Pentru '​prinderea'​ erorilor puteti folosi ​**catch**. </​note>​
 <​code>​ <​code>​
-nav { +  const getAllBooks = useCallback(async () => 
-  ul +    ​const accessToken = await getAccessTokenSilently()
-    ​margin: 0+    ​axiosInstance 
-    ​padding0; +      .get(routes.books.getAll,​ { 
-    ​list-stylenone+        headers{ 
-  }+          ​Authorization`Bearer ${accessToken}`,​ 
 +        }, 
 +      }) 
 +      .then(({ data }) => setBooks(data))
 +  }, [getAccessTokenSilently]);​
  
-  ​li display: inline-block} +  ​const handleAddBook = (form) => { 
- +    (async () => { 
-  ​a ​+      const accessToken = await getAccessTokenSilently()
-    ​displayblock; +      ​axiosInstance 
-    ​padding6px 12px+        ​.post(routes.books.addBook,​ form, 
-    ​text-decoration:​ none+          ​headers{ 
-  } +            ​Authorization`Bearer ${accessToken}`,​ 
-}+          }, 
 +        }) 
 +        .then(() => getAllBooks())
 +    ​})()
 +  };
 </​code>​ </​code>​
  
-**Exemplu folosire mixins** +<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>​
-@mixin transform($property) { +  useEffect(() => 
-  ​-webkit-transform:​ $property+    ​getAllBooks()
-  ​-ms-transform:​ $property;​ +  }, [getAllBooks]);
-  transform: $property;​ +
-} +
-.box {  +
-  @include transform(rotate(30deg));  +
-}+
 </​code>​ </​code>​
  
-==== 6.3 Modules ==== +Un exemplu de cerere de tip DELETE ​avem pentru stergerea unei resurse (carti):
- +
-Pentru ​organizare buna a codului, putem folosi module in care sa tinem culorile, fonturile, dimensiunile folosite in website. +
 <​code>​ <​code>​
-// _base.scss +  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>​
  
-<code> +<note tip>Inainte de stergerea resurseiutilizatorul ar trebui cumva anuntat ​de actiunea acestuia, in caz ca a apasat din gresealaAcest lucru se poate face printr-un pop-up in care sa confirme stergerea.</note
-// styles.scss +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.
-@use '​base';​ +
- +
-.inverse { +
-  background-color:​ base.$primary-color;​ +
-  color: white; +
-+
-</​code>​ +
- +
-==== 6.4 Extend ==== +
- +
-Poate una dintre cele mai utile feature-uri din Sasscu @extend putem sa distribuim proprietati CSS de la un selector la altul. +
- +
-<​code>​ +
-/* This CSS will print because %message-shared is extended. */ +
-%message-shared { +
-  border: 1px solid #ccc; +
-  padding: 10px; +
-  color: #333; +
-+
- +
-// This CSS won't print because %equal-heights is never extended. +
-%equal-heights { +
-  display: flex; +
-  flex-wrap: wrap; +
-+
- +
-.message { +
-  @extend %message-shared;​ +
-+
- +
-.success { +
-  @extend %message-shared;​ +
-  border-color:​ green; +
-+
- +
-.error { +
-  @extend %message-shared;​ +
-  border-color:​ red; +
-+
- +
-.warning { +
-  @extend %message-shared;​ +
-  border-color:​ yellow; +
-+
-</code+
- +
----- +
- +
-===== 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.1618745378.txt.gz · Last modified: 2021/04/18 14:29 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