Kuidas luua ReactJS-i ja Firebase'i abil TodoApp

Tere, inimesed, tere tulemast selle õpetuse juurde. Enne alustamist peaksite olema tuttav põhiliste ReactJS-mõistetega. Kui te pole seda, soovitaksin teil läbi vaadata ReactJSi dokumentatsioon.

Selles rakenduses kasutame järgmisi komponente:

  1. ReactJS
  2. Materiaalne kasutajaliides
  3. Firebase
  4. ExpressJS
  5. Postimees

Kuidas meie rakendus välja näeb:

Rakenduse arhitektuur:

Meie komponentide mõistmine:

Võib tekkida küsimus, miks me selles rakenduses firebase'i kasutame. Noh, see pakub turvalist autentimist , reaalajas andmebaasi , serverivaba komponenti ja salvestusruumi .

Kasutame siin Expressi, et meil pole vaja HTTP-erandeid käsitleda. Kasutame kõiki funktsioonide komponendis firebase'i pakette. Seda seetõttu, et me ei taha oma kliendirakendust liiga suureks muuta, mis kipub kasutajaliidese laadimisprotsessi aeglustama.

Märkus. Jagan selle õpetuse nelja eraldi ossa. Iga jaotise alguses leiate git-pühenduse, millel on selles jaotises välja töötatud kood. Samuti, kui soovite näha täielikku koodi, on see selles hoidlas saadaval.

1. jagu: Todo API-de väljatöötamine

Selleslõik , me arendada neid elemente:

  1. Konfigureerige firebase'i funktsioonid.
  2. Installi Express raamistik ja looge Todo API-d.
  3. Firestore'i seadistamine andmebaasina.

Todo API koodi rakendatakse käesoleva paragrahvi võib leida selles toime.

Firebase'i funktsioonide konfigureerimine:

Minge Firebase'i konsooli.

Valige suvand Lisa projekt . Pärast seda järgige firebase'i projekti konfigureerimiseks samm-sammult allpool olevat gif-i.

Minge vahekaardile funktsioonid ja klõpsake nuppu Alusta :

Näete dialoogiboksi, kus on juhised Firebase'i funktsioonide seadistamise kohta . Minge oma kohalikku keskkonda. Avage käsurea tööriist. Firebase'i tööriistade installimiseks arvutisse kasutage järgmist käsku:

 npm install -g firebase-tools

Kui see on tehtud, kasutage käsku, firebase initet konfigureerida firebase'i funktsioonid oma kohalikus keskkonnas. Firebase'i funktsiooni lähtestamisel kohalikus keskkonnas valige järgmised suvandid:

  1. Milliseid Firebase'i CLI funktsioone soovite selle kausta jaoks seadistada? Funktsioonide valimiseks vajutage tühikut ja seejärel valikute kinnitamiseks sisestusklahvi Enter => Funktsioonid: pilvefunktsioonide konfigureerimine ja juurutamine
  2. Kõigepealt seostame selle projekti kataloogi Firebase'i projektiga .... => Kasutage olemasolevat projekti
  3. Valige selle kataloogi jaoks Firebase'i vaikeprojekt => rakenduse_nimi
  4. Mis keelt soovite kasutada pilvefunktsioonide kirjutamiseks? => JavaScript
  5. Kas soovite kasutada ESLinti tõenäoliste vigade tabamiseks ja stiili jõustamiseks? => N
  6. Kas soovite installida sõltuvused nüüd npm-ga? (Y / n) => Y

Pärast seadistamise tegemist saate järgmise teate:

✔ Firebase initialization complete!

See on meie kataloogistruktuur pärast initsialiseerimise lõpetamist:

+-- firebase.json +-- functions | +-- index.js | +-- node_modules | +-- package-lock.json | +-- package.json

Nüüd avage index.jsfunktsioonide kataloogi all ja kopeerige ja kleepige järgmine kood:

const functions = require('firebase-functions'); exports.helloWorld = functions.https.onRequest((request, response) => { response.send("Hello from Firebase!"); });

Paigaldage kood firebase'i funktsioonidesse järgmise käsu abil:

firebase deploy

Kui juurutamine on tehtud, saate käsurea lõppu järgmise logirea:

> ✔ Deploy complete! > Project Console: //console.firebase.google.com/project/todoapp-/overview

Valige Projektikonsool> Funktsioonid ja sealt leiate API URL-i. URL näeb välja selline:

//-todoapp-.cloudfunctions.net/helloWorld

Kopeerige see URL ja kleepige see brauserisse. Te saate järgmise vastuse:

Hello from Firebase!

See kinnitab, et meie Firebase'i funktsioon on õigesti konfigureeritud.

Installi Express Framework:

Nüüd installime Expressraamistiku oma projekti järgmise käsu abil:

npm i express

Nüüd loome funktsioonide kataloogi sisse API-de kataloogi. Selles kataloogis loome faili nimega . Eemaldage kõik ja kopeerige ja kleepige järgmine kood:todos.jsindex.js

//index.js const functions = require('firebase-functions'); const app = require('express')(); const { getAllTodos } = require('./APIs/todos') app.get('/todos', getAllTodos); exports.api = functions.https.onRequest(app);

Oleme marsruudile / todos määranud funktsiooni getAllTodos . Nii et kõik sellel marsruudil olevad API-kõned teostatakse funktsiooni getAllTodos kaudu. Nüüd minge todos.jsAPI-de kataloogi alla olevasse faili ja siin kirjutame funktsiooni getAllTodos.

//todos.js exports.getAllTodos = (request, response) => { todos = [ { 'id': '1', 'title': 'greeting', 'body': 'Hello world from sharvin shah' }, { 'id': '2', 'title': 'greeting2', 'body': 'Hello2 world2 from sharvin shah' } ] return response.json(todos); }

Siin oleme deklareerinud näidisobjekti JSON. Hiljem tuletame selle Firestore'ist. Kuid esialgu tagastame selle. Nüüd juurutage see käsu abil oma firebase'i funktsiooni firebase deploy. See küsibluba mooduli helloworld kustutamiseks - sisestage lihtsalt y .

The following functions are found in your project but do not exist in your local source code: helloWorld Would you like to proceed with deletion? Selecting no will continue the rest of the deployments. (y/N) y

Kui see on tehtud, minge jaotisse Projektikonsool> Funktsioonid ja sealt leiate API URL-i. API näeb välja selline:

//-todoapp-.cloudfunctions.net/api

Nüüd minge brauserisse ja kopeerige-kleepige URL ning lisage selle URL-i lõppu / todos . Saad järgmise väljundi:

[ { 'id': '1', 'title': 'greeting', 'body': 'Hello world from sharvin shah' }, { 'id': '2', 'title': 'greeting2', 'body': 'Hello2 world2 from sharvin shah' } ]

Firebase Firestore:

Kasutame oma rakenduse jaoks reaalajas andmebaasina firebase firestore'i. Nüüd minge Firebase'i konsoolis jaotisse Konsool > Andmebaas . Firestore'i konfigureerimiseks järgige allolevat GIF-i:

Kui konfiguratsioon on teinud siis klõpsa Start kollektsiooni nuppu ja seadke kollektsiooni nr nagu kõike . Klõpsake nuppu Edasi ja kuvatakse järgmine hüpikaken:

Eirake võtit DocumentID. Sest valdkonnas, tüüp ja väärtus , vaadake JSON allapoole. Värskendage väärtust vastavalt:

{ Field: title, Type: String, Value: Hello World }, { Field: body, Type: String, Value: Hello folks I hope you are staying home... }, { Field: createtAt, type: timestamp, value: Add the current date and time here }

Vajutage nuppu Salvesta. Näete, et kogu ja dokument on loodud. Minge tagasi kohalikku keskkonda. Peame installima selle, firebase-adminmillel on vajalik firestore'i pakett. Selle installimiseks kasutage seda käsku:

npm i firebase-admin

Funktsioonide kataloogi alla saate luua kataloogi nimega util .Minge sellesse kataloogi ja looge failinimi admin.js. Selles failis impordime firebase'i administraatori paketi ja lähtestame firestore'i andmebaasi objekti. Ekspordime selle, et teised moodulid saaksid seda kasutada.

//admin.js const admin = require('firebase-admin'); admin.initializeApp(); const db = admin.firestore(); module.exports = { admin, db };

Nüüd kirjutame nende andmete toomiseks API. Mine todos.jsalla funktsioonid> API kataloogi. Eemaldage vana kood ja kopeerige-kleepige allolev kood:

//todos.js const { db } = require('../util/admin'); exports.getAllTodos = (request, response) => { db .collection('todos') .orderBy('createdAt', 'desc') .get() .then((data) => { let todos = []; data.forEach((doc) => { todos.push({ todoId: doc.id, title: doc.data().title, body: doc.data().body, createdAt: doc.data().createdAt, }); }); return response.json(todos); }) .catch((err) => { console.error(err); return response.status(500).json({ error: err.code}); }); };

Siin toome andmebaasist kõik ülesvõtted ja edastame need loendis kliendile.

Rakenduse saate käitada ka firebase servekäsu abil, selle asemel, et seda iga kord juurutada. Selle käsu käivitamisel võite saada mandaadi osas tõrke. Selle parandamiseks toimige järgmiselt.

  1. Minge projekti seadistustesse (vasakus ülanurgas olev ikoon Seaded)
  2. Minge vahekaardile teenuse kontod  
  3. Allpool on võimalus luua uus võti . Klõpsake seda valikut ja see laadib alla JSON-laiendiga faili.
  4. Peame need volitused oma käsurea seanssi eksportima. Selleks kasutage allolevat käsku:
export GOOGLE_APPLICATION_CREDENTIALS="/home/user/Downloads/[FILE_NAME].json"

Pärast seda käivitage firebase serve käsk. Kui te ikka viga siis kasutage järgmist käsku: firebase login --reauth. See avab brauseris Google'i sisselogimislehe. Kui sisselogimine on tehtud, töötab see ilma tõrgeteta.

Firebase serve käsu käivitamisel leiate URL-i käsurea tööriista logidest. Avage see URL brauseris ja lisage /todospärast seda.

✔ functions[api]: http function initialized (//localhost:5000/todoapp-//api).

Teie brauseris on järgmine JSON-väljund:

[ { "todoId":"W67t1kSMO0lqvjCIGiuI", "title":"Hello World", "body":"Hello folks I hope you are staying home...", "createdAt":{"_seconds":1585420200,"_nanoseconds":0 } } ]

Muude API-de kirjutamine:

On aeg kirjutada kõik muud todo API-d, mida me oma rakenduse jaoks vajame.

  1. Loo Todo üksus: minge index.jsfunktsioonide kataloogi alla. Importige postOneTodo meetod olemasoleva getAllTodose alla. Määrake sellele meetodile ka marsruut POST.
//index.js const { .., postOneTodo } = require('./APIs/todos') app.post('/todo', postOneTodo);

Minge todos.jsfunktsioonide kataloogi ja lisage postOneTodoolemasoleva getAllTodosmeetodi alla uus meetod.

//todos.js exports.postOneTodo = (request, response) => { if (request.body.body.trim() === '') { return response.status(400).json({ body: 'Must not be empty' }); } if(request.body.title.trim() === '') { return response.status(400).json({ title: 'Must not be empty' }); } const newTodoItem = { title: request.body.title, body: request.body.body, createdAt: new Date().toISOString() } db .collection('todos') .add(newTodoItem) .then((doc)=>{ const responseTodoItem = newTodoItem; responseTodoItem.id = doc.id; return response.json(responseTodoItem); }) .catch((err) => { response.status(500).json({ error: 'Something went wrong' }); console.error(err); }); };

Selles meetodis lisame oma andmebaasi uue Todo. Kui meie keha elemendid on tühjad, tagastame vastuse 400 või lisame andmed.

Käivitage käsk firebase serve ja avage postiljonirakendus. Looge uus taotlus ja valige meetodi tüüp POST . Lisage URL ja keha tüüp JSON.

URL: //localhost:5000/todoapp-//api/todo METHOD: POST Body: { "title":"Hello World", "body": "We are writing this awesome API" }

Vajutage saatmisnuppu ja saate järgmise vastuse:

{ "title": "Hello World", "body": "We are writing this awesome API", "createdAt": "2020-03-29T12:30:48.809Z", "id": "nh41IgARCj8LPWBYzjU0" }

2. Kustuta Todo üksus: minge index.jsfunktsioonide kataloogi. Importige meetod deleteTodo olemasoleva postOneTodo alla. Määrake sellele meetodile ka marsruut KUSTUTA.

//index.js const { .., deleteTodo } = require('./APIs/todos') app.delete('/todo/:todoId', deleteTodo);

Minge todos.jsja lisage deleteTodoolemasoleva postOneTodomeetodi alla uus meetod.

//todos.js exports.deleteTodo = (request, response) => { const document = db.doc(`/todos/${request.params.todoId}`); document .get() .then((doc) => { if (!doc.exists) { return response.status(404).json({ error: 'Todo not found' }) } return document.delete(); }) .then(() => { response.json({ message: 'Delete successfull' }); }) .catch((err) => { console.error(err); return response.status(500).json({ error: err.code }); }); };

Selle meetodi abil kustutame Todo oma andmebaasist. Käivitage käsk firebase serve ja minge postiljoni juurde. Looge uus taotlus, valige meetodi tüüp KUSTUTA ja lisage URL.

URL: //localhost:5000/todoapp-//api/todo/ METHOD: DELETE

Vajutage saatmisnuppu ja saate järgmise vastuse:

{ "message": "Delete successfull" }

3. Redigeeri Todo üksust: minge index.jsfunktsioonide kataloogi alla. Importige editTodo meetod olemasoleva deleteTodo alla. Määrake sellele meetodile ka PUT-marsruut.

//index.js const { .., editTodo } = require('./APIs/todos') app.put('/todo/:todoId', editTodo);

Minge todos.jsja lisage editTodoolemasoleva deleteTodomeetodi alla uus meetod.

//todos.js exports.editTodo = ( request, response ) => { if(request.body.todoId || request.body.createdAt){ response.status(403).json({message: 'Not allowed to edit'}); } let document = db.collection('todos').doc(`${request.params.todoId}`); document.update(request.body) .then(()=> { response.json({message: 'Updated successfully'}); }) .catch((err) => { console.error(err); return response.status(500).json({ error: err.code }); }); };

Selles meetodis redigeerime oma andmebaasist Todot. Pidage meeles, et siin ei luba me kasutajal väljad todoId või loodudAt redigeerida. Käivitage käsk firebase serve ja minge postiljoni juurde. Looge uus taotlus, valige meetodi tüübiks PUT ja lisage URL.

URL: //localhost:5000/todoapp-//api/todo/ METHOD: PUT

Vajutage saatmisnuppu ja saate järgmise vastuse:

{ "message": "Updated successfully" }

Seni kataloogistruktuur:

+-- firebase.json +-- functions | +-- API | +-- +-- todos.js | +-- util | +-- +-- admin.js | +-- index.js | +-- node_modules | +-- package-lock.json | +-- package.json | +-- .gitignore

Sellega oleme valmis rakenduse esimese jaotise. Võite jätkata kohvi joomist, teha pausi ja pärast seda töötame kasutaja API-de väljatöötamisel.

2. jagu: Kasutaja API-de arendamine

Selleslõik , me arendada nende osad:

  1. Kasutaja autentimise (sisselogimise ja registreerumise) API.
  2. Hangi ja värskendage kasutaja üksikasjade API-d.
  3. Kasutaja profiilipildi API värskendamine.
  4. Olemasoleva Todo API turvamine.

Selles jaotises rakendatud kasutaja API-koodi leiate sellest kohustusest.

Alustame siis kasutaja autentimise API loomist. Valige Firebase'i konsool> Autentimine.

Klõpsake nupul Seadista sisselogimismeetod . Kasutame kasutaja kinnitamiseks e-posti aadressi ja parooli. Lubage suvand E-post / parool .

Praegu loome oma kasutaja käsitsi. Kõigepealt ehitame sisse Login API. Pärast seda ehitame Sign-Up API.

Minge jaotises Autentimine vahekaardile Kasutajad, sisestage kasutaja üksikasjad ja klõpsake nuppu Lisa kasutaja .

1. Kasutaja sisselogimise API:

Esiteks peame installima firebasepaketi, mis koosneb Firebase'i autentimise teegist, kasutades järgmist käsku:

npm i firebase

Kui installimine on lõpetatud, minge kataloogi funktsioonid> API-d . Siin loome users.jsfaili. Nüüd index.jsimpordime Inside meetodi loginUser ja määrame sellele marsruudi POST.

//index.js const { loginUser } = require('./APIs/users') // Users app.post('/login', loginUser);

Valige Projekti seaded> Üldine ja sealt leiate järgmise kaardi:

Valige veebiikoon ja järgige allpool olevat gif:

Valige suvand Jätka konsooli . Kui see on tehtud, näete JSON-i koos Firebase'i konfiguratsiooniga. Avage funktsioonid> kataloog kataloog ja looge   config.jsfail. Kopeerige ja kleepige sellesse faili järgmine kood:

// config.js module.exports = { apiKey: "............", authDomain: "........", databaseURL: "........", projectId: ".......", storageBucket: ".......", messagingSenderId: "........", appId: "..........", measurementId: "......." };

Asendage ............väärtustega, mille saate jaotises Firebase'i konsool> Projekti seaded> Üldine> teie rakendused> Firebase SD koodilõik> konfiguratsioon .

Kopeerige ja kleepige users.jsfaili järgmine kood :

// users.js const { admin, db } = require('../util/admin'); const config = require('../util/config'); const firebase = require('firebase'); firebase.initializeApp(config); const { validateLoginData, validateSignUpData } = require('../util/validators'); // Login exports.loginUser = (request, response) => { const user = { email: request.body.email, password: request.body.password } const { valid, errors } = validateLoginData(user); if (!valid) return response.status(400).json(errors); firebase .auth() .signInWithEmailAndPassword(user.email, user.password) .then((data) => { return data.user.getIdToken(); }) .then((token) => { return response.json({ token }); }) .catch((error) => { console.error(error); return response.status(403).json({ general: 'wrong credentials, please try again'}); }) };

Siin kontrollime, kas kasutaja esitatud mandaadid on õiged, firebase signInWithEmailAndPassword mooduliga. Kui neil on õigus, siis saadame selle kasutaja loa või 403 oleku koos "vale mandaadiga" sõnumiga.

Nüüd loome validators.jsall funktsioonid> util kataloog. Kopeerige ja kleepige sellesse faili järgmine kood:

// validators.js const isEmpty = (string) => { if (string.trim() === '') return true; else return false; }; exports.validateLoginData = (data) => { let errors = {}; if (isEmpty(data.email)) errors.email = 'Must not be empty'; if (isEmpty(data.password)) errors.password = 'Must not be empty'; return { errors, valid: Object.keys(errors).length === 0 ? true : false }; };

Sellega on meie LoginAPI lõpule viidud. Käivitage firebase servekäsk ja minge postiljoni juurde. Looge uus taotlus, valige meetodi tüübiks POST ja lisage URL ja keha.

URL: //localhost:5000/todoapp-//api/login METHOD: POST Body: { "email":"Add email that is assigned for user in console", "password": "Add password that is assigned for user in console" }

Vajutage postiljonis nuppu Saada päring ja saate järgmise väljundi:

{ "token": ".........." }

Kasutame seda märki järgmises osas, et saada kasutaja üksikasju . Pidage meeles, et see märgis aegub 60 minuti pärast . Uue loa genereerimiseks kasutage seda API-d uuesti.

2. Kasutaja registreerumise API:

Firebase'i vaikimisi autentimismehhanism võimaldab teil salvestada ainult sellist teavet nagu e-post, parool jne. Kuid meil on vaja rohkem teavet selle tuvastamiseks, kas see kasutaja omab seda kasutajat, et nad saaksid sellega lugeda, värskendada ja kustutada.

Selle eesmärgi saavutamiseks loome uue kogu nimega kasutajad . Selle kogu alla salvestame kasutaja andmed, mis kaardistatakse kasutajanime põhjal Todoga. Iga kasutajanimi on kõigi platvormi kasutajate jaoks ainulaadne.

Mine index.js. Importime meetodi signUpUser ja määrame sellele marsruudi POST.

//index.js const { .., signUpUser } = require('./APIs/users') app.post('/signup', signUpUser);

Nüüd minge meetodi validators.jsalla ja lisage järgmine kood validateLoginData.

// validators.js const isEmail = (email) => { const emailRegEx = /^(([^()\[\]\\.,;:\[email protected]"]+(\.[^()\[\]\\.,;:\[email protected]"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; if (email.match(emailRegEx)) return true; else return false; }; exports.validateSignUpData = (data) => { let errors = {}; if (isEmpty(data.email)) { errors.email = 'Must not be empty'; } else if (!isEmail(data.email)) { errors.email = 'Must be valid email address'; } if (isEmpty(data.firstName)) errors.firstName = 'Must not be empty'; if (isEmpty(data.lastName)) errors.lastName = 'Must not be empty'; if (isEmpty(data.phoneNumber)) errors.phoneNumber = 'Must not be empty'; if (isEmpty(data.country)) errors.country = 'Must not be empty'; if (isEmpty(data.password)) errors.password = 'Must not be empty'; if (data.password !== data.confirmPassword) errors.confirmPassword = 'Passowrds must be the same'; if (isEmpty(data.username)) errors.username = 'Must not be empty'; return { errors, valid: Object.keys(errors).length === 0 ? true : false }; };

Nüüd minge mooduli users.jsalla ja lisage järgmine kood loginUser.

// users.js exports.signUpUser = (request, response) => { const newUser = { firstName: request.body.firstName, lastName: request.body.lastName, email: request.body.email, phoneNumber: request.body.phoneNumber, country: request.body.country, password: request.body.password, confirmPassword: request.body.confirmPassword, username: request.body.username }; const { valid, errors } = validateSignUpData(newUser); if (!valid) return response.status(400).json(errors); let token, userId; db .doc(`/users/${newUser.username}`) .get() .then((doc) => { if (doc.exists) { return response.status(400).json({ username: 'this username is already taken' }); } else { return firebase .auth() .createUserWithEmailAndPassword( newUser.email, newUser.password ); } }) .then((data) => { userId = data.user.uid; return data.user.getIdToken(); }) .then((idtoken) => { token = idtoken; const userCredentials = { firstName: newUser.firstName, lastName: newUser.lastName, username: newUser.username, phoneNumber: newUser.phoneNumber, country: newUser.country, email: newUser.email, createdAt: new Date().toISOString(), userId }; return db .doc(`/users/${newUser.username}`) .set(userCredentials); }) .then(()=>{ return response.status(201).json({ token }); }) .catch((err) => { console.error(err); if (err.code === 'auth/email-already-in-use') { return response.status(400).json({ email: 'Email already in use' }); } else { return response.status(500).json({ general: 'Something went wrong, please try again' }); } }); }

Kinnitame oma kasutajaandmed ja pärast seda saadame kasutaja loomiseks mooduli firebase createUserWithEmailAndPassword meilisõnumi ja parooli . Kui kasutaja on edukalt loodud, salvestame kasutaja mandaadid andmebaasi.

Sellega on meie SignUp API valmis. Käivitage firebase servekäsk ja minge postiljoni juurde. Looge uus taotlus, valige meetodi tüübiks POST . Lisage URL ja keha.

URL: //localhost:5000/todoapp-//api/signup METHOD: POST Body: { "firstName": "Add a firstName here", "lastName": "Add a lastName here", "email":"Add a email here", "phoneNumber": "Add a phone number here", "country": "Add a country here", "password": "Add a password here", "confirmPassword": "Add same password here", "username": "Add unique username here" }

Vajutage postiljonis nuppu Saada päring ja saate järgmise väljundi:

{ "token": ".........." }

Nüüd minge Firebase'i konsoolile> Andmebaas ja seal näete järgmist väljundit:

Nagu näete, on meie kasutajate kollektsioon edukalt loodud koos ühe dokumendiga.

3. Laadige üles kasutajaprofiili pilt:

Meie kasutajad saavad oma profiilipildi üles laadida. Selle saavutamiseks kasutame Storage bucket. Valige Firebase'i konsool> Salvestusruum ja klõpsake nuppu Alusta . Konfigureerimiseks järgige allolevat GIF-i:

Nüüd minge jaotise Salvestamine vahekaardile Reeglid ja värskendage ämbrile juurdepääsu luba vastavalt allolevale pildile:

Profiilipildi üleslaadimiseks kasutame paketti nimega busboy. Selle paketi installimiseks kasutage järgmist käsku:

npm i busboy

Mine index.js. Importige meetod uploadProfilePhoto olemasoleva signUpUseri meetodi alla. Määrake sellele meetodile ka marsruut POST.

//index.js const auth = require('./util/auth'); const { .., uploadProfilePhoto } = require('./APIs/users') app.post('/user/image', auth, uploadProfilePhoto);

Siin oleme lisanud autentimiskihi, et ainult selle kontoga seotud kasutaja saaks pildi üles laadida. Nüüd loo fail nimega auth.jsin funktsioonid> utils kataloog. Kopeerige ja kleepige faili järgmine kood:

// auth.js const { admin, db } = require('./admin'); module.exports = (request, response, next) => { let idToken; if (request.headers.authorization && request.headers.authorization.startsWith('Bearer ')) { idToken = request.headers.authorization.split('Bearer ')[1]; } else { console.error('No token found'); return response.status(403).json({ error: 'Unauthorized' }); } admin .auth() .verifyIdToken(idToken) .then((decodedToken) => { request.user = decodedToken; return db.collection('users').where('userId', '==', request.user.uid).limit(1).get(); }) .then((data) => { request.user.username = data.docs[0].data().username; request.user.imageUrl = data.docs[0].data().imageUrl; return next(); }) .catch((err) => { console.error('Error while verifying token', err); return response.status(403).json(err); }); };

Siin kasutame märgi kontrollimiseks moodulit firebase confirmIdToken . Pärast seda dekodeerime kasutajaandmed ja edastame need olemasolevale päringule.

Minge users.jsja lisage signupmeetodi alla järgmine kood :

// users.js deleteImage = (imageName) => { const bucket = admin.storage().bucket(); const path = `${imageName}` return bucket.file(path).delete() .then(() => { return }) .catch((error) => { return }) } // Upload profile picture exports.uploadProfilePhoto = (request, response) => { const BusBoy = require('busboy'); const path = require('path'); const os = require('os'); const fs = require('fs'); const busboy = new BusBoy({ headers: request.headers }); let imageFileName; let imageToBeUploaded = {}; busboy.on('file', (fieldname, file, filename, encoding, mimetype) => { if (mimetype !== 'image/png' && mimetype !== 'image/jpeg') { return response.status(400).json({ error: 'Wrong file type submited' }); } const imageExtension = filename.split('.')[filename.split('.').length - 1]; imageFileName = `${request.user.username}.${imageExtension}`; const filePath = path.join(os.tmpdir(), imageFileName); imageToBeUploaded = { filePath, mimetype }; file.pipe(fs.createWriteStream(filePath)); }); deleteImage(imageFileName); busboy.on('finish', () => { admin .storage() .bucket() .upload(imageToBeUploaded.filePath, { resumable: false, metadata: { metadata: { contentType: imageToBeUploaded.mimetype } } }) .then(() => { const imageUrl = `//firebasestorage.googleapis.com/v0/b/${config.storageBucket}/o/${imageFileName}?alt=media`; return db.doc(`/users/${request.user.username}`).update({ imageUrl }); }) .then(() => { return response.json({ message: 'Image uploaded successfully' }); }) .catch((error) => { console.error(error); return response.status(500).json({ error: error.code }); }); }); busboy.end(request.rawBody); };

Sellega on meie profiilipildi üleslaadimise API valmis. Käivitage firebase servekäsk ja minge postiljoni juurde. Looge uus taotlus, valige meetodi tüüp POST , lisage URL ja valige jaotises keha tüüp vormandmetena.

Taotlus on kaitstud, nii et peate saatma ka esitaja märgi . Kandja märgi saatmiseks logige uuesti sisse, kui luba on aegunud. Pärast seda valige Postmani rakendus> vahekaart Volitamine> Tüüp> Kandja tunnus ja kleepige märgisektsioonis märk.

URL: //localhost:5000/todoapp-//api/user/image METHOD: GET Body: { REFER THE IMAGE down below }

Vajutage postiljonis nuppu Saada päring ja saate järgmise väljundi:

{ "message": "Image uploaded successfully" }

4. Hankige kasutaja üksikasjad:

Siin toome andmebaasist oma kasutaja andmeid. Minge index.jsmeetodile getUserDetail ja importige see ning määrake sellele GET-marsruut.

// index.js const { .., getUserDetail } = require('./APIs/users') app.get('/user', auth, getUserDetail);

Nüüd minge mooduli juurde users.jsja lisage järgmine kood pärast uploadProfilePhotomoodulit:

// users.js exports.getUserDetail = (request, response) => { let userData = {}; db .doc(`/users/${request.user.username}`) .get() .then((doc) => { if (doc.exists) { userData.userCredentials = doc.data(); return response.json(userData); } }) .catch((error) => { console.error(error); return response.status(500).json({ error: error.code }); }); }

Kasutajaandmete tuletamiseks kasutame moodulit firebase doc (). Get () . Sellega on meie GET kasutaja üksikasjade API valmis. Käivitage firebase servekäsk ja minge postiljoni juurde. Looge uus taotlus, valige meetodi tüüp: GET , lisage URL ja keha.

Taotlus on kaitstud, nii et peate saatma ka esitaja märgi . Kandja märgi saatmiseks logige uuesti sisse, kui luba on aegunud.

URL: //localhost:5000/todoapp-//api/user METHOD: GET

Vajutage postiljonis nuppu Saada päring ja saate järgmise väljundi:

{ "userCredentials": { "phoneNumber": "........", "email": "........", "country": "........", "userId": "........", "username": "........", "createdAt": "........", "lastName": "........", "firstName": "........" } }

5. Värskendage kasutaja üksikasju:

Lisame nüüd kasutajaandmete värskendamiseks funktsionaalsuse. Minge index.jsja kopeerige ja kleepige järgmine kood:

// index.js const { .., updateUserDetails } = require('./APIs/users') app.post('/user', auth, updateUserDetails);

Nüüd minge users.jsja lisage updateUserDetailsmoodul olemasoleva alla getUserDetails:

// users.js exports.updateUserDetails = (request, response) => { let document = db.collection('users').doc(`${request.user.username}`); document.update(request.body) .then(()=> { response.json({message: 'Updated successfully'}); }) .catch((error) => { console.error(error); return response.status(500).json({ message: "Cannot Update the value" }); }); }

Siin kasutame firebase'i värskendusmeetodit . Sellega on meie kasutajate üksikasjade värskendamise API valmis. Taotluse puhul järgige sama protseduuri nagu ülaltoodud kasutaja üksikasjade hankimise API-s ühe muudatusega. Lisage siia päringusse keha ja meetod POST-iga.

URL: //localhost:5000/todoapp-//api/user METHOD: POST Body : { // You can edit First Name, last Name and country // We will disable other Form Tags from our UI }

Vajutage postiljonis nuppu Saada päring ja saate järgmise väljundi:

{ "message": "Updated successfully" }

6. Todo API-de turvamine:

Todo API turvamiseks, et ainult valitud kasutaja saaks sellele juurde pääseda, teeme mõned muudatused meie olemasolevas koodis. Esiteks värskendame meie index.jsjärgmiselt:

// index.js // Todos app.get('/todos', auth, getAllTodos); app.get('/todo/:todoId', auth, getOneTodo); app.post('/todo',auth, postOneTodo); app.delete('/todo/:todoId',auth, deleteTodo); app.put('/todo/:todoId',auth, editTodo);

Oleme värskendanud kõiki Todo marsruute , lisades authnii, et kõik API-kõned nõuavad luba ja neile pääseb juurde ainult konkreetne kasutaja.

Pärast seda Mine todos.jsalla funktsioonid> API kataloogi.

  1. Todo API loomine: avage todos.jsja lisage postOneTodo meetodi alla kasutajanime võti järgmiselt:
const newTodoItem = { .., username: request.user.username, .. }

2. GET All Todos API: avage meetodi getAllTodostodos.js all ja lisage klausel where järgmiselt:

db .collection('todos') .where('username', '==', request.user.username) .orderBy('createdAt', 'desc')

Käivitage firebase'i teenus ja testige meie GET API-d. Ärge unustage esituskoodi saatmist. Siit saate vastuse vea järgmiselt:

{ "error": 9 }

Minge käsureale ja näete logis järgmisi ridu:

i functions: Beginning execution of "api"> Error: 9 FAILED_PRECONDITION: The query requires an index. You can create it here: > at callErrorFromStatus

Avage see brauseris ja klõpsake käsku Loo register.

Kui register on koostatud, saatke päring uuesti ja saate järgmise väljundi:

[ { "todoId": "......", "title": "......", "username": "......", "body": "......", "createdAt": "2020-03-30T13:01:58.478Z" } ]

3.   Kustuta Todo API: avage meetodi DeleteTodotodos.js all ja lisage järgmine tingimus. Lisa see tingimus sees document.get (). Seejärel () päringu alla ! Doc.exists seisukorras.

.. if(doc.data().username !== request.user.username){ return response.status(403).json({error:"UnAuthorized"}) }

Seni kataloogistruktuur:

+-- firebase.json +-- functions | +-- API | +-- +-- todos.js | +-- +-- users.js | +-- util | +-- +-- admin.js | +-- +-- auth.js | +-- +-- validators.js | +-- index.js | +-- node_modules | +-- package-lock.json | +-- package.json | +-- .gitignore

Sellega oleme oma API taustaprogrammi lõpule viinud. Tehke paus, jooge kohv ja pärast seda hakkame oma rakenduse esiosa ehitama

3. jagu: kasutaja juhtpaneel

Selleslõik , me arendada nende osad:

  1. ReactJS ja materjali kasutajaliidese seadistamine.
  2. Sisselogimis- ja registreerumisvormi loomine.
  3. Ehituskonto sektsioon.

Selles jaotises rakendatud kasutaja juhtpaneeli koodi leiate sellest kohustusest.

1. ReactJS ja materjali kasutajaliidese seadistamine:

Kasutame malli loomine-reageerimine-rakendust. See annab meile rakenduse arendamiseks põhimõttelise struktuuri. Selle installimiseks kasutage järgmist käsku:

npm install -g create-react-app

Minge projekti juurkausta, kus asub funktsioonide kataloog. Initsialiseerige meie esiotsa rakendus järgmise käsu abil:

create-react-app view

Pea meeles, et kasutada versiooni v16.13.1 kohtaReactJS raamatukogu .

Kui installimine on lõpule jõudnud, näete oma käsurea logides järgmist:

cd view npm start Happy hacking!

Sellega oleme oma Reacti rakenduse konfigureerinud. Saad järgmise kataloogistruktuuri:

+-- firebase.json +-- functions { This Directory consists our API logic } +-- view { This Directory consists our FrontEnd Compoenents } +-- .firebaserc +-- .gitignore

Nüüd käivitage rakendus käsu abil npm start. Minge brauserisse //localhost:3000/ja näete järgmist väljundit:

Nüüd eemaldame kõik mittevajalikud komponendid. Minge kuvakataloogi ja eemaldage kõik failidmille ees on [Eemalda] . Selleks vaadake allolevat kataloogipuu struktuuri.

+-- README.md [ Remove ] +-- package-lock.json +-- package.json +-- node_modules +-- .gitignore +-- public | +-- favicon.ico [ Remove ] | +-- index.html | +-- logo192.png [ Remove ] | +-- logo512.png [ Remove ] | +-- manifest.json | +-- robots.txt +-- src | +-- App.css | +-- App.test.js | +-- index.js | +-- serviceWorker.js | +-- App.js | +-- index.css [ Remove ] | +-- logo.svg [ Remove ] | +-- setupTests.js

Minge index.htmlavaliku kataloogi alla ja eemaldage järgmised read:

Nüüd minge App.jskataloogi src alla ja asendage vana kood järgmise koodiga:

import React from 'react'; function App() { return ( ); } export default App;

Minge index.jsja eemaldage järgmine import:

import './index.css'

Ma ei ole kustutanud App.cssega kasuta seda selles rakenduses. Kuid kui soovite seda kustutada või kasutada, võite seda teha.

Minge brauserisse //localhost:3000/ja kuvatakse tühi ekraaniväljund.

Materjali kasutajaliidese installimiseks minge kuvakataloogi ja kopeerige see käsk terminali:

npm install @material-ui/core

Ärge unustage kasutada materjali kasutajaliidese teegi versiooni v4.9.8 .

2. Sisselogimisvorm:

Sisselogimisvormi väljatöötamiseks minge aadressile App.js. App.jsLisage järgmise impordi ülaossa :

import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'; import login from './pages/login';

Kasutame oma TodoAppi marsruutide määramiseks lülitit ja marsruuti . Praegu lisame ainult / login marsruudi ja määrame sellele sisselogimiskomponendi.

// App.js 

Loo lehekülge kataloogi alusel olemasolevate arvates kataloog ja faili nimega login.jsall lehekülge kataloogis.

Materjalide kasutajaliidese komponendid ja Axiose pakett imporditakse järgmisse login.js:

// login.js // Material UI components import React, { Component } from 'react'; import Avatar from '@material-ui/core/Avatar'; import Button from '@material-ui/core/Button'; import CssBaseline from '@material-ui/core/CssBaseline'; import TextField from '@material-ui/core/TextField'; import Link from '@material-ui/core/Link'; import Grid from '@material-ui/core/Grid'; import LockOutlinedIcon from '@material-ui/icons/LockOutlined'; import Typography from '@material-ui/core/Typography'; import withStyles from '@material-ui/core/styles/withStyles'; import Container from '@material-ui/core/Container'; import CircularProgress from '@material-ui/core/CircularProgress'; import axios from 'axios';

Lisame oma sisselogimislehele järgmised stiilid:

// login.js const styles = (theme) => ({ paper: { marginTop: theme.spacing(8), display: 'flex', flexDirection: 'column', alignItems: 'center' }, avatar: { margin: theme.spacing(1), backgroundColor: theme.palette.secondary.main }, form: { width: '100%', marginTop: theme.spacing(1) }, submit: { margin: theme.spacing(3, 0, 2) }, customError: { color: 'red', fontSize: '0.8rem', marginTop: 10 }, progess: { position: 'absolute' } });

Loome klassi nimega sisselogimine, millel on vorm, ja esitame selle sees käitleja.

// login.js class login extends Component { constructor(props) { super(props); this.state = { email: '', password: '', errors: [], loading: false }; } componentWillReceiveProps(nextProps) { if (nextProps.UI.errors) { this.setState({ errors: nextProps.UI.errors }); } } handleChange = (event) => { this.setState({ [event.target.name]: event.target.value }); }; handleSubmit = (event) => { event.preventDefault(); this.setState({ loading: true }); const userData = { email: this.state.email, password: this.state.password }; axios .post('/login', userData) .then((response) => { localStorage.setItem('AuthToken', `Bearer ${response.data.token}`); this.setState({ loading: false, }); this.props.history.push('/'); }) .catch((error) => { this.setState({ errors: error.response.data, loading: false }); }); }; render() { const { classes } = this.props; const { errors, loading } = this.state; return ( Login      Sign In {loading && }     {"Don't have an account? Sign Up"}    {errors.general && (  {errors.general}  )} ); } }

Selle faili lõppu lisage järgmine eksport:

export default withStyles(styles)(login); 

Lisage meie Firebase'i funktsioonide URL, et vaadata> package.json järgmiselt:

Pidage meeles: lisage olemasoleva brauseriloendi JSON-objekti alla võti nimega puhverserver
"proxy": "//-todoapp-.cloudfunctions.net/api"

Installige Axiosi ja materjali ikooni pakett järgmiste käskude abil:

// Axios command: npm i axios // Material Icons: npm install @material-ui/icons

Lisasime sisse sisselogimise marsruudi App.js. Selles login.jsoleme loonud klassi komponendi, mis tegeleb olekuga, saadab postitustaotluse Axiosi paketi abil sisselogimis-API-le. Kui taotlus on edukas, salvestame loa. Kui vastuses ilmneb vigu, renderdame need lihtsalt kasutajaliideses.

Minge brauserisse aadressil //localhost:3000/loginja näete järgmist sisselogimisliidest.

Proovige täita valed mandaadid või saata tühi taotlus ja saate vead. Saada kehtiv taotlus. Valige arendajakonsool> Rakendus . Näete, et kasutajate luba on kohalikus salvestusruumis. Kui sisselogimine on edukas, suunatakse meid tagasi avalehele.

3. Registreerimisvorm:

Registreerimisvormi arendamiseks minge App.jsja värskendage olemasolevat Routekomponenti alloleva reaga:

// App.js 

Ärge unustage importida:

// App.js import signup from './pages/signup';

Loo fail nimega signup.jsall lehekülgi kataloog .

Signup.js-ist impordime paketi Materjali kasutajaliides ja Axios:

// signup.js import React, { Component } from 'react'; import Avatar from '@material-ui/core/Avatar'; import Button from '@material-ui/core/Button'; import CssBaseline from '@material-ui/core/CssBaseline'; import TextField from '@material-ui/core/TextField'; import Link from '@material-ui/core/Link'; import Grid from '@material-ui/core/Grid'; import LockOutlinedIcon from '@material-ui/icons/LockOutlined'; import Typography from '@material-ui/core/Typography'; import Container from '@material-ui/core/Container'; import withStyles from '@material-ui/core/styles/withStyles'; import CircularProgress from '@material-ui/core/CircularProgress'; import axios from 'axios';

Lisame oma registreerimislehele järgmised stiilid:

// signup.js const styles = (theme) => ({ paper: { marginTop: theme.spacing(8), display: 'flex', flexDirection: 'column', alignItems: 'center' }, avatar: { margin: theme.spacing(1), backgroundColor: theme.palette.secondary.main }, form: { width: '100%', // Fix IE 11 issue. marginTop: theme.spacing(3) }, submit: { margin: theme.spacing(3, 0, 2) }, progess: { position: 'absolute' } }); 

Loome klassi nimega registreerumine, millel on vorm, ja esitame selle sees käitleja.

// signup.js class signup extends Component { constructor(props) { super(props); this.state = { firstName: '', lastName: '', phoneNumber: '', country: '', username: '', email: '', password: '', confirmPassword: '', errors: [], loading: false }; } componentWillReceiveProps(nextProps) { if (nextProps.UI.errors) { this.setState({ errors: nextProps.UI.errors }); } } handleChange = (event) => { this.setState({ [event.target.name]: event.target.value }); }; handleSubmit = (event) => { event.preventDefault(); this.setState({ loading: true }); const newUserData = { firstName: this.state.firstName, lastName: this.state.lastName, phoneNumber: this.state.phoneNumber, country: this.state.country, username: this.state.username, email: this.state.email, password: this.state.password, confirmPassword: this.state.confirmPassword }; axios .post('/signup', newUserData) .then((response) => { localStorage.setItem('AuthToken', `${response.data.token}`); this.setState({ loading: false, }); this.props.history.push('/'); }) .catch((error) => { this.setState({ errors: error.response.data, loading: false }); }); }; render() { const { classes } = this.props; const { errors, loading } = this.state; return ( Sign up                              Sign Up {loading && }     Already have an account? Sign in ); } }

Selle faili lõppu lisage järgmine eksport:

export default withStyles(styles)(signup); 

Registreerimiskomponendi loogika on sama, mis sisselogimiskomponent. Minge brauserisse aadressil //localhost:3000/signupja näete järgmist registreerimisliidest. Kui registreerimine on edukas, suunatakse meid tagasi avalehele.

Proovige täita valed mandaadid või saata tühi taotlus ja saate vead. Saada kehtiv taotlus. Valige arendajakonsool> Rakendus . Näete, et kasutajate luba on kohalikus salvestusruumis.

4. Konto sektsioon:

Konto lehe loomiseks peame kõigepealt looma oma avalehe , kust laadime konto jaotise . Minge App.jsja värskendage järgmist marsruuti:

// App.js 

Ärge unustage importi:

// App.js import home from './pages/home';

Looge uus nimega fail home.js. See fail on meie rakenduse register. Mõlemad jaotised Konto ja Todo laaditakse sellel lehel nupu klõpsamise põhjal.

Importige Materiali kasutajaliidese paketid, Axiose pakett, meie kohandatud konto, todokomponendid ja vahevara autentimine.

// home.js import React, { Component } from 'react'; import axios from 'axios'; import Account from '../components/account'; import Todo from '../components/todo'; import Drawer from '@material-ui/core/Drawer'; import AppBar from '@material-ui/core/AppBar'; import CssBaseline from '@material-ui/core/CssBaseline'; import Toolbar from '@material-ui/core/Toolbar'; import List from '@material-ui/core/List'; import Typography from '@material-ui/core/Typography'; import Divider from '@material-ui/core/Divider'; import ListItem from '@material-ui/core/ListItem'; import ListItemIcon from '@material-ui/core/ListItemIcon'; import ListItemText from '@material-ui/core/ListItemText'; import withStyles from '@material-ui/core/styles/withStyles'; import AccountBoxIcon from '@material-ui/icons/AccountBox'; import NotesIcon from '@material-ui/icons/Notes'; import Avatar from '@material-ui/core/avatar'; import ExitToAppIcon from '@material-ui/icons/ExitToApp'; import CircularProgress from '@material-ui/core/CircularProgress'; import { authMiddleWare } from '../util/auth'

Me määrame oma sahtli laiuse järgmiselt:

const drawerWidth = 240;

Lisame oma kodulehele järgmise stiili:

const styles = (theme) => ({ root: { display: 'flex' }, appBar: { zIndex: theme.zIndex.drawer + 1 }, drawer: { width: drawerWidth, flexShrink: 0 }, drawerPaper: { width: drawerWidth }, content: { flexGrow: 1, padding: theme.spacing(3) }, avatar: { height: 110, width: 100, flexShrink: 0, flexGrow: 0, marginTop: 20 }, uiProgess: { position: 'fixed', zIndex: '1000', height: '31px', width: '31px', left: '50%', top: '35%' }, toolbar: theme.mixins.toolbar });

Loome klassi nimega kodu. Sellel klassil on API-kõne, et saada kasutaja profiilipilt, eesnimi ja perekonnanimi. Samuti on loogika valida, millist komponenti kuvada, kas Todo või konto:

class home extends Component { state = { render: false }; loadAccountPage = (event) => { this.setState({ render: true }); }; loadTodoPage = (event) => { this.setState({ render: false }); }; logoutHandler = (event) => { localStorage.removeItem('AuthToken'); this.props.history.push('/login'); }; constructor(props) { super(props); this.state = { firstName: '', lastName: '', profilePicture: '', uiLoading: true, imageLoading: false }; } componentWillMount = () => { authMiddleWare(this.props.history); const authToken = localStorage.getItem('AuthToken'); axios.defaults.headers.common = { Authorization: `${authToken}` }; axios .get('/user') .then((response) => { console.log(response.data); this.setState({ firstName: response.data.userCredentials.firstName, lastName: response.data.userCredentials.lastName, email: response.data.userCredentials.email, phoneNumber: response.data.userCredentials.phoneNumber, country: response.data.userCredentials.country, username: response.data.userCredentials.username, uiLoading: false, profilePicture: response.data.userCredentials.imageUrl }); }) .catch((error) => { if(error.response.status === 403) { this.props.history.push('/login') } console.log(error); this.setState({ errorMsg: 'Error in retrieving the data' }); }); }; render() { const { classes } = this.props; if (this.state.uiLoading === true) { return ( {this.state.uiLoading && } ); } else { return ( TodoApp 

{' '} {this.state.firstName} {this.state.lastName}

{' '} {' '} {' '} {' '} {' '} {' '} {this.state.render ? : } ); } } }

Siin koodis näete, et authMiddleWare(this.props.history);seda kasutatakse. See vahevara kontrollib, kas authToken on null. Kui jah, siis see lükkab kasutaja tagasi login.js. See lisati nii, et meie kasutaja ei pääse /marsruudile ilma registreerumata ega sisse logimata. Selle faili lõppu lisage järgmine eksport:

export default withStyles(styles)(home); 

Nüüd mõtlete, mida see kood home.jsteeb?

 {this.state.render ?  : } 

See kontrollib renderdamise olekut, mille määrame nupuvajutusega. Loome komponentkataloogi ja selle kataloogi all kaks faili: account.jsja todo.js.

Loome kataloogi nimega util ja selle kataloogi nime auth.js. Kopeerige ja kleepige järgmine kood jaotisse auth.js:

export const authMiddleWare = (history) => { const authToken = localStorage.getItem('AuthToken'); if(authToken === null){ history.push('/login') } }

Korraks on todo.jsfaili, kirjutame lihtsalt klassi, mis renderdab teksti Tere, ma olen väike . Töötame järgmises jaotises oma tööde kallal:

import React, { Component } from 'react' import withStyles from '@material-ui/core/styles/withStyles'; import Typography from '@material-ui/core/Typography'; const styles = ((theme) => ({ content: { flexGrow: 1, padding: theme.spacing(3), }, toolbar: theme.mixins.toolbar, }) ); class todo extends Component { render() { const { classes } = this.props; return ( Hello I am todo   ) } } export default (withStyles(styles)(todo));

Nüüd on aeg konto jaotise juurde. Importige meie kasutajaliidese Materjali kasutajaliides, clsx, axios ja authmiddleWare account.js.

// account.js import React, { Component } from 'react'; import withStyles from '@material-ui/core/styles/withStyles'; import Typography from '@material-ui/core/Typography'; import CircularProgress from '@material-ui/core/CircularProgress'; import CloudUploadIcon from '@material-ui/icons/CloudUpload'; import { Card, CardActions, CardContent, Divider, Button, Grid, TextField } from '@material-ui/core'; import clsx from 'clsx'; import axios from 'axios'; import { authMiddleWare } from '../util/auth';

Lisame oma konto lehele järgmise stiili:

// account.js const styles = (theme) => ({ content: { flexGrow: 1, padding: theme.spacing(3) }, toolbar: theme.mixins.toolbar, root: {}, details: { display: 'flex' }, avatar: { height: 110, width: 100, flexShrink: 0, flexGrow: 0 }, locationText: { paddingLeft: '15px' }, buttonProperty: { position: 'absolute', top: '50%' }, uiProgess: { position: 'fixed', zIndex: '1000', height: '31px', width: '31px', left: '50%', top: '35%' }, progess: { position: 'absolute' }, uploadButton: { marginLeft: '8px', margin: theme.spacing(1) }, customError: { color: 'red', fontSize: '0.8rem', marginTop: 10 }, submitButton: { marginTop: '10px' } });

Loome klassi komponendi nimega konto. Praegu kopeerige ja kleepige järgmine kood:

// account.js class account extends Component { constructor(props) { super(props); this.state = { firstName: '', lastName: '', email: '', phoneNumber: '', username: '', country: '', profilePicture: '', uiLoading: true, buttonLoading: false, imageError: '' }; } componentWillMount = () => { authMiddleWare(this.props.history); const authToken = localStorage.getItem('AuthToken'); axios.defaults.headers.common = { Authorization: `${authToken}` }; axios .get('/user') .then((response) => { console.log(response.data); this.setState({ firstName: response.data.userCredentials.firstName, lastName: response.data.userCredentials.lastName, email: response.data.userCredentials.email, phoneNumber: response.data.userCredentials.phoneNumber, country: response.data.userCredentials.country, username: response.data.userCredentials.username, uiLoading: false }); }) .catch((error) => { if (error.response.status === 403) { this.props.history.push('/login'); } console.log(error); this.setState({ errorMsg: 'Error in retrieving the data' }); }); }; handleChange = (event) => { this.setState({ [event.target.name]: event.target.value }); }; handleImageChange = (event) => { this.setState({ image: event.target.files[0] }); }; profilePictureHandler = (event) => { event.preventDefault(); this.setState({ uiLoading: true }); authMiddleWare(this.props.history); const authToken = localStorage.getItem('AuthToken'); let form_data = new FormData(); form_data.append('image', this.state.image); form_data.append('content', this.state.content); axios.defaults.headers.common = { Authorization: `${authToken}` }; axios .post('/user/image', form_data, { headers: { 'content-type': 'multipart/form-data' } }) .then(() => { window.location.reload(); }) .catch((error) => { if (error.response.status === 403) { this.props.history.push('/login'); } console.log(error); this.setState({ uiLoading: false, imageError: 'Error in posting the data' }); }); }; updateFormValues = (event) => { event.preventDefault(); this.setState({ buttonLoading: true }); authMiddleWare(this.props.history); const authToken = localStorage.getItem('AuthToken'); axios.defaults.headers.common = { Authorization: `${authToken}` }; const formRequest = { firstName: this.state.firstName, lastName: this.state.lastName, country: this.state.country }; axios .post('/user', formRequest) .then(() => { this.setState({ buttonLoading: false }); }) .catch((error) => { if (error.response.status === 403) { this.props.history.push('/login'); } console.log(error); this.setState({ buttonLoading: false }); }); }; render() { const { classes, ...rest } = this.props; if (this.state.uiLoading === true) { return ( {this.state.uiLoading && }  ); } else { return ( {this.state.firstName} {this.state.lastName}  

Selle faili lõppu lisage järgmine eksport:

export default withStyles(styles)(account); 

In account.json palju komponente kasutatakse. Kõigepealt vaatame, kuidas meie rakendus välja näeb. Pärast seda selgitan kõiki komponente, mida kasutatakse ja miks neid kasutatakse.

Minge brauserisse ja kui teie luba on aegunud, suunab see teid   loginlehele. Lisage oma andmed ja logige uuesti sisse. Kui olete seda teinud, minge vahekaardile Konto ja leiate järgmise kasutajaliidese:

Konto jaotises on 3 käitlejat:

  1. componentWillMount : See on Reacti sisseehitatud olelusringi meetod. Kasutame seda andmete renderdamise elutsükli eel andmete laadimiseks ja olekuväärtuste värskendamiseks.
  2. ProfilePictureUpdate: see on meie kohandatud käitleja, mida me kasutame, nii et kui meie kasutaja klõpsab nupul Laadi foto üles, saadab ta andmed serverisse ja laadib lehe uuesti, et kuvada kasutaja uus profiilipilt.
  3. updateFormValues: See on ka meie kohandatud käitleja, et uuendada kasutaja üksikasju. Siin saab kasutaja uuendada oma eesnime, perekonnanime ja riiki. Me ei luba e-posti ja kasutajanime värskendusi, kuna meie taustaprogrammi loogika sõltub nendest võtmetest.

Peale nende kolme käitleja on vormileht, mille peal on stiil. Siin on kataloogistruktuur kuni selle hetkeni vaate kaustas:

+-- public +-- src | +-- components | +-- +-- todo.js | +-- +-- account.js | +-- pages | +-- +-- home.js | +-- +-- login.js | +-- +-- signup.js | +-- util | +-- +-- auth.js | +-- README.md | +-- package-lock.json | +-- package.json | +-- .gitignore

Sellega oleme lõpetanud oma konto juhtpaneeli. Minge nüüd kohvi jooma, tehke paus ja järgmises jaotises ehitame Todo armatuurlaua.

4. jagu: Todo juhtpaneel

Selleslõik , me arendada UI nende omadused Todos Armatuurlaud:

  1. Lisage Todo:
  2. Hankige kõik ülesanded:
  3. Todo kustutamine
  4. Redigeerige todot
  5. Hankige Todo
  6. Teema rakendamine

Selles jaotises rakendatud Todo juhtpaneeli koodi leiate siit.

Mine todos.jsalla komponendid kataloog. Lisage olemasolevale impordile järgmine import:

import Button from '@material-ui/core/Button'; import Dialog from '@material-ui/core/Dialog'; import AddCircleIcon from '@material-ui/icons/AddCircle'; import AppBar from '@material-ui/core/AppBar'; import Toolbar from '@material-ui/core/Toolbar'; import IconButton from '@material-ui/core/IconButton'; import CloseIcon from '@material-ui/icons/Close'; import Slide from '@material-ui/core/Slide'; import TextField from '@material-ui/core/TextField'; import Grid from '@material-ui/core/Grid'; import Card from '@material-ui/core/Card'; import CardActions from '@material-ui/core/CardActions'; import CircularProgress from '@material-ui/core/CircularProgress'; import CardContent from '@material-ui/core/CardContent'; import MuiDialogTitle from '@material-ui/core/DialogTitle'; import MuiDialogContent from '@material-ui/core/DialogContent'; import axios from 'axios'; import dayjs from 'dayjs'; import relativeTime from 'dayjs/plugin/relativeTime'; import { authMiddleWare } from '../util/auth';

Samuti peame olemasolevatesse stiilikomponentidesse lisama järgmised CSS-i elemendid:

const styles = (theme) => ({ .., // Existing CSS elements title: { marginLeft: theme.spacing(2), flex: 1 }, submitButton: { display: 'block', color: 'white', textAlign: 'center', position: 'absolute', top: 14, right: 10 }, floatingButton: { position: 'fixed', bottom: 0, right: 0 }, form: { width: '98%', marginLeft: 13, marginTop: theme.spacing(3) }, toolbar: theme.mixins.toolbar, root: { minWidth: 470 }, bullet: { display: 'inline-block', margin: '0 2px', transform: 'scale(0.8)' }, pos: { marginBottom: 12 }, uiProgess: { position: 'fixed', zIndex: '1000', height: '31px', width: '31px', left: '50%', top: '35%' }, dialogeStyle: { maxWidth: '50%' }, viewRoot: { margin: 0, padding: theme.spacing(2) }, closeButton: { position: 'absolute', right: theme.spacing(1), top: theme.spacing(1), color: theme.palette.grey[500] } });

Lisame hüpiku dialoogiboksi ülemineku:

const Transition = React.forwardRef(function Transition(props, ref) { return ; });

Eemaldage olemasolev Todo klass ja kopeerige-kleepige järgmine klass:

class todo extends Component { constructor(props) { super(props); this.state = { todos: '', title: '', body: '', todoId: '', errors: [], open: false, uiLoading: true, buttonType: '', viewOpen: false }; this.deleteTodoHandler = this.deleteTodoHandler.bind(this); this.handleEditClickOpen = this.handleEditClickOpen.bind(this); this.handleViewOpen = this.handleViewOpen.bind(this); } handleChange = (event) => { this.setState({ [event.target.name]: event.target.value }); }; componentWillMount = () => { authMiddleWare(this.props.history); const authToken = localStorage.getItem('AuthToken'); axios.defaults.headers.common = { Authorization: `${authToken}` }; axios .get('/todos') .then((response) => { this.setState({ todos: response.data, uiLoading: false }); }) .catch((err) => { console.log(err); }); }; deleteTodoHandler(data) { authMiddleWare(this.props.history); const authToken = localStorage.getItem('AuthToken'); axios.defaults.headers.common = { Authorization: `${authToken}` }; let todoId = data.todo.todoId; axios .delete(`todo/${todoId}`) .then(() => { window.location.reload(); }) .catch((err) => { console.log(err); }); } handleEditClickOpen(data) { this.setState({ title: data.todo.title, body: data.todo.body, todoId: data.todo.todoId, buttonType: 'Edit', open: true }); } handleViewOpen(data) { this.setState({ title: data.todo.title, body: data.todo.body, viewOpen: true }); } render() { const DialogTitle = withStyles(styles)((props) => { const { children, classes, onClose, ...other } = props; return (  {children} {onClose ? (    ) : null}  ); }); const DialogContent = withStyles((theme) => ({ viewRoot: { padding: theme.spacing(2) } }))(MuiDialogContent); dayjs.extend(relativeTime); const { classes } = this.props; const { open, errors, viewOpen } = this.state; const handleClickOpen = () => { this.setState({ todoId: '', title: '', body: '', buttonType: '', open: true }); }; const handleSubmit = (event) => { authMiddleWare(this.props.history); event.preventDefault(); const userTodo = { title: this.state.title, body: this.state.body }; let options = {}; if (this.state.buttonType === 'Edit') { options = { url: `/todo/${this.state.todoId}`, method: 'put', data: userTodo }; } else { options = { url: '/todo', method: 'post', data: userTodo }; } const authToken = localStorage.getItem('AuthToken'); axios.defaults.headers.common = { Authorization: `${authToken}` }; axios(options) .then(() => { this.setState({ open: false }); window.location.reload(); }) .catch((error) => { this.setState({ open: true, errors: error.response.data }); console.log(error); }); }; const handleViewClose = () => { this.setState({ viewOpen: false }); }; const handleClose = (event) => { this.setState({ open: false }); }; if (this.state.uiLoading === true) { return ( {this.state.uiLoading && }  ); } else { return ( {this.state.buttonType === 'Edit' ? 'Edit Todo' : 'Create a new Todo'}   {this.state.buttonType === 'Edit' ? 'Save' : 'Submit'}                {this.state.todos.map((todo) => (     {todo.title}   {dayjs(todo.createdAt).fromNow()}   {`${todo.body.substring(0, 65)}`}     this.handleViewOpen({ todo })}> {' '} View{' '}   this.handleEditClickOpen({ todo })}> Edit   this.deleteTodoHandler({ todo })}> Delete     ))}    {this.state.title}       ); } } }

Selle faili lõppu lisage järgmine eksport:

export default withStyles(styles)(todo); 

Kõigepealt mõistame, kuidas meie kasutajaliides töötab, ja pärast seda mõistame koodi. Minge brauserisse ja saate järgmise kasutajaliidese:

Klõpsake paremas alanurgas nuppu Lisa ja saate järgmise ekraani:

Lisage Todo pealkiri ja üksikasjad ning vajutage nuppu Esita. Kuvatakse järgmine ekraan:

Pärast seda klõpsake nuppu vaade ja näete Todo täielikke üksikasju:

Klõpsake nuppu Muuda ja saate todot muuta:

Klõpsake nuppu Kustuta ja saate Todo kustutada. Nüüd, kui oleme teadlikud juhtpaneeli toimimisest, mõistame selles kasutatud komponente.

1. Lisa Todo: lisamise lisamiseks rakendame materiaalse kasutajaliidese komponenti Dialoog. See komponent rakendab konksu funktsionaalsust. Kasutame klasse, nii et eemaldame selle funktsionaalsuse.

// This sets the state to open and buttonType flag to add: const handleClickOpen = () => { this.setState({ todoId: '', title: '', body: '', buttonType: '', open: true }); }; // This sets the state to close: const handleClose = (event) => { this.setState({ open: false }); };

Peale selle muudame ka Add Todo nupu asukohta.

// Position our button floatingButton: { position: 'fixed', bottom: 0, right: 0 }, 

Nüüd asendame loendi sildi selle dialoogi sees oleva vormiga. See aitab meid uue todo lisamisel.

// Show Edit or Save depending on buttonType state {this.state.buttonType === 'Edit' ? 'Save' : 'Submit'} // Our Form to add a todo    // TextField here   // TextField here   

Thekäepide Esitakoosneb buttonTypeoleku lugemise loogikast . Kui olek on tühi string (“”), postitatakse see Add Todo API-sse. Kui olek on Editsiis selle stsenaariumi korral, värskendab see redigeerimisfunktsiooni.

2. Hankige Todos: kasutatavate todode kuvamiseks Grid containerja selle sees asetame Grid item. Selle sees kasutame Cardandmete kuvamiseks komponenti.

 {this.state.todos.map((todo) => (    // Here will show Todo with view, edit and delete button   ))} 

Kasutame kaarti todoüksuse kuvamiseks, kui API saadab need loendisse. Enne renderdamise teostamist oleku saamiseks ja seadistamiseks kasutame komponentiWillMount elutsüklit. Nuppe on 3 ( vaade, muutmine ja kustutamine ), seega vajame nupul klõpsamisel toimingu tegemiseks kolme käitlejat. Nende nuppude kohta saame teada nende vastavatest alajaotustest.

3. Redigeeri Todot: redigeerimise Todo jaoks kasutame uuesti dialoogi hüpikakoodi, mida kasutatakse Todo lisamisel. Nupuklõpsude eristamiseks kasutame buttonTypeolekut. Add Todo jaoks on   buttonTypeolek (“”)samal ajal kui redigeerimiseks see on Edit.

handleEditClickOpen(data) { this.setState({ .., buttonType: 'Edit', .. }); }

Kui handleSubmitmeetod loeme buttonTyperiigi ja seejärel saadab taotluse vastavalt.

4. Kustuta Todo: kui sellel nupul klõpsatakse, saadame todoobjekti meie deleteTodoHandlerile ja seejärel saadab see päringu edasi taustaprogrammile.

 this.deleteTodoHandler({ todo })}>Delete

5. Vaade Todo: andmete kuvamisel oleme need kärpinud, et kasutaja saaks pilgu sellest, millega tegelik on seotud. Kuid kui kasutaja soovib selle kohta rohkem teada saada, peab ta klõpsama nupul Vaade.

Selleks kasutame dialoogi Kohandatud. Selle sees kasutame DialogTitle ja DialogContent. See kuvab meie pealkirja ja sisu. DialougeContent'is kasutame vormi kasutaja postitatud sisu kuvamiseks. (See on üks lahendus, mille leidsin palju ja võite vabalt proovida muud.)

// This is used to remove the underline of the Form InputProps={{ disableUnderline: true }} // This is used so that user cannot edit the data readonly

6. Teema rakendamine: see on meie rakenduse viimane samm. Rakendame oma rakenduses teema. Selleks kasutame createMuiThemeja ThemeProvidermateriaalset kasutajaliidest. Kopeerige ja kleepige järgmine kood App.js:

import { ThemeProvider as MuiThemeProvider } from '@material-ui/core/styles'; import createMuiTheme from '@material-ui/core/styles/createMuiTheme'; const theme = createMuiTheme({ palette: { primary: { light: '#33c9dc', main: '#FF5722', dark: '#d50000', contrastText: '#fff' } } }); function App() { return (  // Router and switch will be here.  ); }

Tundsime rakendades teema meie nupp todo.json CardActions. Lisage vaate, muutmise ja kustutamise nupu värvimärgend.

Minge brauserisse ja leiate, et kõik on sama, välja arvatud see, et rakendus on erinevat värvi.

Ja oleme valmis! ReactJS ja Firebase abil oleme loonud TodoAppi. Kui olete selle üles ehitanud kuni selle hetkeni, siis palju õnne teile selle saavutuse puhul.

Võtke julgelt ühendust Twitteris ja Githubis.