Hogyan készítsünk TodoApp-ot a ReactJS és a Firebase használatával

Helló emberek, üdvözöljük ezt a bemutatót. Mielőtt elkezdenénk, ismernie kell az alapvető ReactJS fogalmakat. Ha nem, javasoljuk, hogy olvassa el a ReactJS dokumentációját.

A következő összetevőket fogjuk használni ebben az alkalmazásban:

  1. ReactJS
  2. Anyagi felhasználói felület
  3. Firebase
  4. ExpressJS
  5. Postás

Hogyan fog kinézni az alkalmazásunk:

Alkalmazás architektúra:

Komponenseink megértése:

Kíváncsi lehet, miért használjuk a Firebase-t ebben az alkalmazásban. Nos, ez biztosítja a biztonságos hitelesítés , a Valós idejű adatbázis , egy szerver nélküli komponens, valamint egy tároló vödör .

Az Express-t itt használjuk, hogy ne kelljen kezelnünk a HTTP-kivételeket. Az összes firebase csomagot használni fogjuk a funkciók összetevőjében. Ennek oka az, hogy nem akarjuk túl nagyra növelni az ügyfélalkalmazásunkat, ami általában lassítja az UI betöltési folyamatát.

Megjegyzés: Ezt az oktatóanyagot négy külön szakaszra osztom. Minden szakasz elején talál egy git-elköteleződést, amelynek kódja az adott szakaszban kifejlesztett. Ha a teljes kódot szeretné látni, akkor ez elérhető ebben a tárban.

1. szakasz: Todo API-k fejlesztése

Ebbenrész , fogunk fejleszteni ezeket az elemeket:

  1. Konfigurálja a firebase funkciókat.
  2. Telepítse az Express keretrendszert és építse fel a Todo API-kat.
  3. A tűzoltó adatbázis konfigurálása.

Az ebben a szakaszban megvalósított Todo API-kód ezen az elkötelezettségen található.

Konfigurálja a Firebase funkciókat:

Lépjen a Firebase konzolhoz.

Válassza a Projekt hozzáadása lehetőséget. Ezután kövesse az alábbi gif-et lépésről lépésre a firebase projekt konfigurálásához.

Lépjen a funkciók fülre, és kattintson az Első lépések gombra:

Megjelenik egy párbeszédpanel, amely utasításokat tartalmaz a Firebase funkciók beállításáról . Menjen a helyi környezetbe. Nyissa meg a parancssori eszközt. A Firebase eszközök telepítéséhez használja az alábbi parancsot:

 npm install -g firebase-tools

Miután ez megtörtént, használja a parancsot firebase inita Firebase funkcióinak konfigurálásához a helyi környezetben. Válassza ki a következő lehetőségeket, amikor inicializálja a firebase funkciót a helyi környezetben:

  1. Mely Firebase CLI szolgáltatásokat kívánja beállítani ehhez a mappához? Nyomja meg a Szóköz gombot a szolgáltatások kiválasztásához, majd az Enter billentyűt a választások megerősítéséhez => Funkciók: Felhőfunkciók konfigurálása és telepítése
  2. Először társítsuk ezt a projektkönyvtárat egy Firebase projekthez .... => Használjon meglévő projektet
  3. Válasszon alapértelmezett Firebase-projektet ehhez a könyvtárhoz => alkalmazásnév
  4. Milyen nyelven szeretne felhőfunkciókat írni? => JavaScript
  5. Szeretné használni az ESLint programot a lehetséges hibák fogására és a stílus érvényesítésére? => N
  6. Szeretné most telepíteni a függőségeket az npm segítségével? (I / N) => Y

A konfigurálás befejezése után a következő üzenetet kapja:

✔ Firebase initialization complete!

Az inicializálás befejeztével ez lesz a könyvtárstruktúránk:

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

Most nyissa meg a index.jsfüggvénykönyvtár alatt, és másolja be a következő kódot:

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

Telepítse a kódot a Firebase függvényekbe a következő paranccsal:

firebase deploy

A telepítés befejezése után a következő logline jelenik meg a parancssor végén:

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

Lépjen a Projekt konzol> Funkciók lehetőségre, és ott megtalálja az API URL-jét. Az URL a következőképpen fog kinézni:

//-todoapp-.cloudfunctions.net/helloWorld

Másolja ezt az URL-t, és illessze be a böngészőbe. A következő választ kapja:

Hello from Firebase!

Ez megerősíti, hogy a Firebase funkciónk megfelelően van konfigurálva.

Telepítse az Express keretrendszert:

Telepítsük a Expresskeretet a projektünkbe a következő paranccsal:

npm i express

Most hozzunk létre egy API- könyvtárat a függvénykönyvtárban . A könyvtárban létrehozunk egy nevű fájlt todos.js. Távolítson el mindent a fájlból, index.jsmajd másolja be a következő kódot:

//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);

A getAllTodos függvényt hozzárendeltük a / todos útvonalhoz. Tehát ezen az útvonalon az összes API-hívás a getAllTodos függvényen keresztül fog végrehajtani. Most lépjen todos.jsaz API-k könyvtár alatti fájlba, és itt megírjuk a getAllTodos függvényt.

//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); }

Itt deklaráltunk egy minta JSON objektumot. Később ezt a Firestore-ból fogjuk levezetni. De egyelőre ezt visszaküldjük. Most telepítse ezt a Firebase funkcióba a parancs használatával firebase deploy. Meg fogja kérdeznia helloworld modul törléséhez - csak írja be 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

Ha ez megtörtént, lépjen a Projekt konzol> Funkciók lehetőségre, és ott megtalálja az API URL-jét. Az API így fog kinézni:

//-todoapp-.cloudfunctions.net/api

Most lépjen a böngészőhöz, és másolja be az URL-t, és adja hozzá / todos az URL végén. A következő kimenetet kapja:

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

Firebase Firestore:

Az alkalmazásunkhoz valós idejű adatbázisként egy firebase firestore-t fogunk használni. Most lépjen a Konzol> Adatbázis elemre a Firebase konzolban. A tűzoltó konfigurálásához kövesse az alábbi gif-et:

Ha a konfigurációs történik majd a Indítás Gyűjtemény gombot és állítsa Gyűjteményazonosító a todos . Kattintson a Tovább gombra, és a következő felugró ablak jelenik meg:

Hagyja figyelmen kívül a DocumentID kulcsot. A mező, típus és érték tekintetében lásd az alábbi JSON-t. Ennek megfelelően frissítse az értéket:

{ 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 }

Nyomja meg a mentés gombot. Látni fogja, hogy a gyűjtemény és a dokumentum létrejön. Térjen vissza a helyi környezetbe. Telepítenünk kell a szükséges firebase-adminfirestore csomagot. A telepítéshez használja ezt a parancsot:

npm i firebase-admin

Hozzon létre egy util nevű könyvtárat a függvénykönyvtár alatt .Lépjen ebbe a könyvtárba, és hozzon létre egy fájlnevet admin.js. Ebben a fájlban importáljuk a firebase admin csomagot és inicializáljuk a firestore adatbázis objektumot. Ezt exportálni fogjuk, hogy más modulok is használhassák.

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

Most írjunk egy API-t az adatok lekéréséhez. Lépjen todos.jsa függvények> API-k könyvtár alatt. Távolítsa el a régi kódot, és másolja be az alábbi kódot:

//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}); }); };

Itt lekérjük az összes témát az adatbázisból, és listában továbbítjuk az ügyfélnek.

Az alkalmazást a firebase serveparancs használatával helyben is futtathatja, ahelyett, hogy minden alkalommal telepítené. A parancs futtatásakor hibaüzenetet kaphat a hitelesítő adatokkal kapcsolatban. Javításához hajtsa végre az alábbi lépéseket:

  1. Lépjen a Projektbeállítások (Beállítások ikonra a bal felső sarokban)
  2. Lépjen a szolgáltatásfiókok fülre  
  3. Lent lesz lehetőség új kulcs előállítására . Kattintson erre a lehetőségre, és letölti a JSON kiterjesztésű fájlt.
  4. Exportálnunk kell ezeket a hitelesítő adatokat a parancssori munkamenetünkbe. Ehhez használja az alábbi parancsot:
export GOOGLE_APPLICATION_CREDENTIALS="/home/user/Downloads/[FILE_NAME].json"

Ezt követően futtassa a firebase serve parancsot. Ha továbbra is hibaüzenetet kap, akkor használja a következő parancsot: firebase login --reauth. Megnyitja a Google bejelentkezési oldalát egy böngészőben. Miután a bejelentkezés megtörtént, hiba nélkül működik.

A firebase serve parancs futtatásakor URL-t talál a parancssori eszköz naplóiban. Nyissa meg ezt az URL-t a böngészőben, és csatolja /todosutána.

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

A következő JSON kimenetet kapja böngészőjében:

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

Egyéb API-k írása:

Itt az ideje megírni az összes többi Todo API-t, amelyekre szükségünk lesz az alkalmazásunkhoz.

  1. Todo elem létrehozása: Menjen index.jsa függvénykönyvtár alatt. A postOneTodo metódus importálása a meglévő getAllTodos alatt. Ezenkívül rendelje hozzá a POST útvonalat ehhez a módszerhez.
//index.js const { .., postOneTodo } = require('./APIs/todos') app.post('/todo', postOneTodo);

Lépjen todos.jsa function könyvtárba, és adjon hozzá egy új módszert postOneTodoa meglévő getAllTodosmetódushoz.

//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); }); };

Ebben a módszerben új Todo-t adunk az adatbázisunkhoz. Ha testünk elemei üresek, akkor 400-as választ adunk vissza, különben hozzáadjuk az adatokat.

Futtassa a firebase serve parancsot, és nyissa meg a postás alkalmazást. Hozzon létre egy új kérést, és válassza ki a módszer típusát POSTként . Adja hozzá az URL-t és a JSON típusú törzset.

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

Nyomja meg a küldés gombot, és a következő választ kapja:

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

2. A Todo elem törlése: Menjen index.jsa függvénykönyvtár alatt. Importálja a deleteTodo metódust a meglévő postOneTodo alá. Rendelje hozzá a DELETE útvonalat is ehhez a módszerhez.

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

Lépjen a todos.jsés hozzá egy új metódust deleteTodoa meglévő postOneTodometódus alatt.

//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 }); }); };

Ezzel a módszerrel egy Todot törölünk az adatbázisunkból. Futtassa a firebase serve parancsot, és menjen a postáshoz. Hozzon létre egy új kérést, válassza ki a módszer típusát DELETE néven, és adja hozzá az URL-t.

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

Nyomja meg a küldés gombot, és a következő választ kapja:

{ "message": "Delete successfull" }

3. A Todo elem szerkesztése: Menjen index.jsa függvénykönyvtár alatt. Importálja az editTodo metódust a meglévő deleteTodo alá. Rendelje hozzá a PUT útvonalat is ehhez a módszerhez.

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

Lépjen a todos.jsés hozzá egy új metódust editTodoa meglévő deleteTodometódus alatt.

//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 }); }); };

Ebben a módszerben egy Todot szerkesztünk az adatbázisunkból. Ne feledje, hogy itt nem engedélyezzük a felhasználó számára a todoId vagy a createdAt mezők szerkesztését. Futtassa a firebase serve parancsot, és menjen a postáshoz. Hozzon létre egy új kérést, válassza ki a módszer típusát PUT- ként , és adja hozzá az URL-t.

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

Nyomja meg a küldés gombot, és a következő választ kapja:

{ "message": "Updated successfully" }

A könyvtár szerkezete eddig:

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

Ezzel befejeztük az alkalmazás első szakaszát. Folytathat egy kis kávét, tarthat egy kis szünetet, és utána dolgozunk a felhasználói API fejlesztésén.

2. szakasz: Felhasználói API-k fejlesztése

Ebbenrész , fogunk fejleszteni ezeket a komponenseket:

  1. Felhasználói hitelesítés (bejelentkezés és regisztráció) API.
  2. GET and Update user details API.
  3. Frissítse a felhasználói profilkép API-t.
  4. A meglévő Todo API biztosítása.

Az ebben a szakaszban megvalósított felhasználói API-kód ezen a kötelezettségvállaláson található.

Kezdjük tehát felépíteni a Felhasználói hitelesítés API-t. Lépjen a Firebase konzol> Hitelesítés elemre.

Kattintson a Set up bejelentkezési módszer gombra. E-mailt és jelszót fogunk használni a felhasználói ellenőrzéshez. Engedélyezze az E-mail / jelszó opciót.

Most kézzel fogjuk létrehozni a felhasználónkat. Először felépítjük a Login API-t. Ezt követően elkészítjük a Sign-Up API-t.

Lépjen a Felhasználók fülre a Hitelesítés részben, töltse ki a Felhasználó adatait, majd kattintson a Felhasználó hozzáadása gombra.

1. Felhasználói bejelentkezési API:

Először telepítenünk kell firebasea Firebase Authentication könyvtárból álló csomagot a következő paranccsal:

npm i firebase

A telepítés befejezése után lépjen a függvények> API-k könyvtárba. Itt létrehozunk egy users.jsfájlt. Most az Inside index.jsegy loginUser metódust importálunk, és hozzárendeljük hozzá a POST útvonalat.

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

Lépjen a Projektbeállítások> Általános elemre, és ott megtalálja a következő kártyát:

Válassza ki a webikont, majd kövesse az alábbi gif-et:

Válassza a Folytatás a konzolhoz lehetőséget. Miután ez megtörtént, megjelenik egy JSON firebase konfigurációval. Lépjen a functions> util könyvtárba, és hozzon létre egy   config.jsfájlt. Másolja be a következő kód beillesztését a fájlba:

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

Cserélje ............a Firebase konzol> Projektbeállítások> Általános> az alkalmazások> Firebase SD-kódrészlet> konfiguráció alatt kapott értékekre .

Másolja be a következő kód beillesztését a users.jsfájlba:

// 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'}); }) };

Itt egy firebase signInWithEmailAndPassword modult használunk annak ellenőrzésére, hogy a felhasználó által benyújtott hitelesítő adatok helyesek-e. Ha igazuk van, akkor elküldjük az adott felhasználó jogkivonatát, vagy pedig egy 403-as státuszt "hibás hitelesítő adatok" üzenettel.

Most hozzuk létre validators.jsa függvények> util könyvtár alatt. Másolja be a következő kód beillesztését a fájlba:

// 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 }; };

Ezzel elkészült a LoginAPI . Futtassa a firebase serveparancsot, és menjen a postáshoz. Hozzon létre egy új kérést, válassza ki a módszer típusát POSTként , majd adja hozzá az URL-t és a törzset.

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" }

Nyomja meg a küldési kérelem gombot a postáson, és a következő kimenetet kapja:

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

Ezt a tokent egy következő részben fogjuk használni a felhasználói adatok megszerzéséhez . Ne feledje, hogy a token 60 perc múlva lejár . Új token létrehozásához használja újra ezt az API-t.

2. Felhasználói regisztráció API:

A firebase alapértelmezett hitelesítési mechanizmusa csak olyan információk tárolását teszi lehetővé, mint az e-mail, a jelszó stb. De további információkra van szükségünk annak azonosításához, hogy ez a felhasználó rendelkezik-e azzal a feladattal, hogy olvasási, frissítési és törlési műveleteket hajtsanak végre rajta.

E cél elérése érdekében létrehozunk egy új, felhasználók néven ismert gyűjteményt . Ebben a gyűjteményben tároljuk a felhasználó adatait, amelyeket a felhasználónév alapján leképezünk a todóra. Minden felhasználónév egyedi lesz a platform minden felhasználója számára.

Menj a index.js. Importálunk egy signUpUser metódust, és hozzárendeljük hozzá a POST útvonalat.

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

Most lépjen a validators.jsés a validateLoginDatamódszer alá a következő kóddal .

// 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 }; };

Most lépjen users.jsa következőhöz, és adja hozzá a következő kódot a loginUsermodul alá.

// 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' }); } }); }

Ellenőrizzük felhasználói adatainkat, majd ezt követően e-mailt és jelszót küldünk a firebase createUserWithEmailAndPassword modulnak a felhasználó létrehozásához. A felhasználó sikeres létrehozása után elmentjük a felhasználói hitelesítő adatokat az adatbázisba.

Ezzel elkészült a SignUp API . Futtassa a firebase serveparancsot, és menjen a postáshoz. Hozzon létre egy új kérést, válassza ki a módszer típusát POSTként . Adja meg az URL-t és a törzset.

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" }

Nyomja meg a postai küldési kérelem gombot, és a következő kimenetet kapja:

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

Most lépjen a Firebase konzol> Adatbázis elemre, és ott a következő kimenetet fogja látni:

Mint láthatja, felhasználóink ​​gyűjteményét sikeresen létrehozták, benne egyetlen dokumentummal.

3. Felhasználói profilkép feltöltése:

Felhasználóink ​​feltölthetik profilképüket. Ennek eléréséhez tároló vödröt fogunk használni. Lépjen a Firebase konzol> Tárhely elemre, és kattintson az Első lépések gombra. A konfiguráláshoz kövesse az alábbi GIF-et:

Most lépjen a Szabályok fülre a Tárolás alatt, és frissítse a csoport hozzáférésének engedélyét az alábbi kép szerint:

A profilkép feltöltéséhez a megnevezett csomagot fogjuk használni busboy. A csomag telepítéséhez használja a következő parancsot:

npm i busboy

Menj index.js. Importálja a uploadProfilePhoto metódust a meglévő signUpUser módszer alá. Rendelje hozzá a POST útvonalat is ehhez a módszerhez.

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

Itt hozzáadtunk egy hitelesítési réteget, hogy csak a fiókhoz társított felhasználó tölthesse fel a képet. Most hozzon létre egy fájl nevet auth.jsa functions> utils könyvtárban. Másolja be a következő kód beillesztését a fájlba:

// 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); }); };

Itt a firebase verifyIdToken modult használjuk a token ellenőrzéséhez. Ezt követően dekódoljuk a felhasználói adatokat és átadjuk azokat a meglévő kérelemnek.

Lépjen a users.jsés adja hozzá a következő kódot a signupmódszer alá:

// 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); };

Ezzel elkészült a Profilkép feltöltése API- nk . Futtassa a firebase serveparancsot, és menjen a postáshoz. Hozzon létre egy új kérést, válassza ki a módszer típusát POSTként , adja hozzá az URL-t, és a törzs szakaszban válassza ki a típust űrlapadatként.

A kérés védett, ezért el kell küldenie a hordozó tokent is. A hordozó token elküldéséhez jelentkezzen be újra, ha a token lejárt. Ezt követően a Postás alkalmazás> Engedélyezés lap> Típus> Bearer Token elemre, és a token szakaszba illessze be a tokent.

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

Nyomja meg a postai küldési kérelem gombot, és a következő kimenetet kapja:

{ "message": "Image uploaded successfully" }

4. Felhasználói adatok letöltése:

Itt lekérjük felhasználónk adatait az adatbázisból. Lépjen a index.jsés importálja a getUserDetail metódust, és rendelje hozzá a GET útvonalat.

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

Most lépjen a users.jsés adja hozzá a következő kódot a uploadProfilePhotomodul után :

// 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 }); }); }

A firebase doc (). Get () modult használjuk a felhasználói adatok levezetésére. Ezzel elkészült a GET Felhasználói adatok API . Futtassa a firebase serveparancsot, és menjen a postáshoz. Hozzon létre egy új kérést, válassza ki a módszer típusát: GET , és adja hozzá az URL-t és a törzset.

A kérés védett, ezért el kell küldenie a hordozó tokent is. A hordozó token elküldéséhez jelentkezzen be újra, ha a token lejárt.

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

Nyomja meg a postai küldési kérelem gombot, és a következő kimenetet kapja:

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

5. Frissítse a felhasználói adatokat:

Most adjuk hozzá a funkciókat a felhasználói adatok frissítéséhez. Lépjen index.jsa következő kódra, és másolja be a következő kódot:

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

Most lépjen a users.jsés adja hozzá a updateUserDetailsmodult a meglévő alá 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" }); }); }

Itt a firebase frissítési módszert használjuk. Ezzel elkészült a Felhasználó adatainak frissítése API . Kövesse ugyanazt az eljárást egy kéréshez, mint a fenti Felhasználói adatok beolvasása API-val, egy változtatással. Adja meg itt a kérelem törzsét, és a metódust POST-ként.

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 }

Nyomja meg a postai küldési kérelem gombot, és a következő kimenetet kapja:

{ "message": "Updated successfully" }

6. A Todo API-k védelme:

A Todo API biztonságának biztosítása érdekében, hogy csak a kiválasztott felhasználó férhessen hozzá, néhány változtatást végrehajtunk a meglévő kódunkban. Először index.jsa következőképpen frissítjük :

// 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);

Frissítettük az összes Todo útvonalat hozzáadásával, authígy az összes API híváshoz tokenre lesz szükség, és csak az adott felhasználó férhet hozzá.

Ezt követően lépjen todos.jsa függvények> API-k könyvtár alatt.

  1. Todo API létrehozása: Nyissa meg a todos.jsés a postOneTodo metódus alatt, és adja hozzá a felhasználónév kulcsot az alábbiak szerint:
const newTodoItem = { .., username: request.user.username, .. }

2. GET All Todos API: Nyissa meg a todos.jsés a getAllTodos metódus alatt adja hozzá a where záradékot az alábbiak szerint:

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

Futtassa a firebase szervert és tesztelje a GET API-t. Ne felejtsd el elküldeni a hordozó jelzőt. Itt a következő válaszhibát kapja:

{ "error": 9 }

Menjen a parancssorba, és a következő sorokat naplózza:

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

Nyissa meg ezt a böngészőben, és kattintson az index létrehozása elemre.

Az index felépítése után küldje el újra a kérést, és a következő kimenetet kapja:

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

3. A   Todo API törlése: Nyissa meg a todos.jsés a deleteTodo metódus alatt adja hozzá a következő feltételt. Adja hozzá ezt a feltételt a document.get (). Majd () lekérdezéshez a ! Doc.exists feltétel alatt.

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

A könyvtár felépítése eddig:

+-- 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

Ezzel elkészült az API háttérprogramunk. Tartson egy kis szünetet, igyon egy kávét, és utána elkezdjük építeni az alkalmazásunk elejét

3. szakasz: Felhasználói irányítópult

Ebbenrész , fogunk fejleszteni ezeket a komponenseket:

  1. Konfigurálja a ReactJS és az anyag felhasználói felületét.
  2. Belépési és feliratkozási űrlap kiépítése.
  3. Épületszámla szakasz.

Az ebben a szakaszban megvalósított felhasználói irányítópult kód ezen a kötelezettségvállaláson található.

1. Konfigurálja a ReactJS és az anyag felhasználói felületét:

A create-reagál-alkalmazás sablont fogjuk használni. Ez alapvető struktúrát biztosít számunkra az alkalmazás fejlesztéséhez. Telepítéséhez használja a következő parancsot:

npm install -g create-react-app

Lépjen a projekt gyökérmappájába, ahol a függvénykönyvtár található. Inicializálja a kezelőfelületet a következő paranccsal:

create-react-app view

Emlékezz arra, hogy változata v16.13.1 aa ReactJS könyvtár .

A telepítés befejezése után a következőket látja a parancssori naplókban:

cd view npm start Happy hacking!

Ezzel konfiguráltuk a React alkalmazást. A következő könyvtárszerkezetet kapja:

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

Most futtassa az alkalmazást a parancs segítségével npm start. Lépjen be a böngészőbe, //localhost:3000/és a következő kimenetet fogja látni:

Most eltávolítjuk az összes felesleges alkatrészt. Lépjen a nézet könyvtárba, majd távolítsa el az összes fájltamelyek előtt [Eltávolítás] található. Ehhez lásd az alábbi könyvtárfa struktúrát.

+-- 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

Lépjen index.htmla nyilvános könyvtár alá, és távolítsa el a következő sorokat:

Most menjen App.jsaz src könyvtár alatt, és cserélje le a régi kódot a következő kóddal:

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

Lépjen index.jsa következőre, és távolítsa el a következő importálást:

import './index.css'

Nem töröltem az alkalmazást, App.cssés nem is használom. De ha törölni vagy használni akarja, akkor ezt szabadon megteheti.

Nyissa meg a böngészőt, //localhost:3000/és üres képernyő kimenetet kap.

A Material felhasználói felület telepítéséhez lépjen a nézet könyvtárba, és másolja be a parancsot a terminálba:

npm install @material-ui/core

Ne felejtse el használni a Material UI könyvtár v4.9.8 verzióját .

2. Bejelentkezés:

Fejleszteni a bejelentkezési űrlap Ide App.js. A tetején adja App.jshozzá a következő importokat:

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

A Switch és Route segítségével útvonalakat rendelünk a TodoApp-hoz. Most csak a / login útvonalat adjuk hozzá, és hozzárendelünk hozzá egy bejelentkezési komponenst.

// App.js 

Hozzon létre egy oldalt könyvtár a meglévő nézet könyvtárat és a fájl neve login.jsmellett a lapok könyvtárban.

A Material UI összetevőket és az Axios csomagot a következőkbe importáljuk 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';

A következő stílusokat adjuk hozzá bejelentkezési oldalunkhoz:

// 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' } });

Létrehozunk egy bejelentkezési osztályt, amelynek van űrlapja, és beküldjük benne a kezelőt.

// 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}  )} ); } }

A fájl végén adja hozzá a következő exportálást:

export default withStyles(styles)(login); 

Adja hozzá a Firebase függvények URL-jét a > package.json megtekintéséhez az alábbiak szerint:

Ne feledje: Adjon hozzá egy proxy nevű kulcsot a meglévő böngészőlista JSON objektum alá
"proxy": "//-todoapp-.cloudfunctions.net/api"

Telepítse az Axios és az anyag ikon csomagot a következő parancsok használatával:

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

Van hozzá egy bejelentkezési útvonalon App.js. Az login.jsáltalunk létrehozott egy osztályt komponens, amely rendezi az állam, elküldi a poszt kérést a bejelentkezési API használatával Axios csomagot. Ha a kérés sikeres, akkor tároljuk a tokent. Ha hibákat kapunk a válaszban, akkor egyszerűen megjelenítjük őket a felhasználói felületen.

Lépjen a böngészőhöz //localhost:3000/logina következő címen, és a következő bejelentkezési felület jelenik meg.

Próbálja meg kitölteni a hibás hitelesítő adatokat, vagy küldjön egy üres kérést, és megkapja a hibákat. Küldjön érvényes kérést. Lépjen a Fejlesztői konzol> Alkalmazás menüpontra . Látni fogja, hogy a felhasználói token a helyi tárolóban van tárolva. Miután a bejelentkezés sikeres volt, visszavezetünk a kezdőlapra.

3. Regisztrációs űrlap:

A regisztrációs űrlap fejlesztéséhez lépjen a webhelyre, App.jsés frissítse a meglévő Routeösszetevőt az alábbi sorral:

// App.js 

Ne felejtse el importálni:

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

Hozzon létre egy fájlt signup.jsaz oldalak könyvtárában .

A signup.js-ben importáljuk az Material UI és az Axios csomagot:

// 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';

A következő stílusokat adjuk fel a regisztrációs oldalunkra:

// 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' } }); 

Létrehozunk egy regisztráció nevű osztályt, amelynek van űrlapja, és beküldjük benne a kezelőt.

// 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 ); } }

A fájl végén adja hozzá a következő exportálást:

export default withStyles(styles)(signup); 

A Regisztráció komponens logikája megegyezik a bejelentkezési összetevővel. Lépjen a böngészőhöz //localhost:3000/signupa következő címen, és a következő regisztrációs felhasználói felület jelenik meg. Miután a regisztráció sikeres volt, visszatérünk a kezdőlapra.

Próbálja meg kitölteni a hibás hitelesítő adatokat, vagy küldjön egy üres kérést, és megkapja a hibákat. Küldjön érvényes kérést. Lépjen a Fejlesztői konzol> Alkalmazás menüpontra . Látni fogja, hogy a felhasználói token a helyi tárolóban van tárolva.

4. Számla szakasz:

A fiókoldal felépítéséhez először létre kell hoznunk a kezdőlapunkat , ahonnan betöltöttük a fiók szakaszt . Lépjen a App.jsés frissítse a következő útvonalat:

// App.js 

Ne felejtsd el az importálást:

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

Hozzon létre egy új nevű fájlt home.js. Ez a fájl lesz az alkalmazásunk indexe. A Fiók és a Todo szakasz a gombra kattintás alapján töltődik be erre az oldalra.

Importálja a Material felhasználói felület csomagokat, az Axios csomagot, az egyéni fiókunkat, a tényleges összetevőket és az autentikus köztes szoftvert.

// 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'

A fiók szélességét a következőképpen állítjuk be:

const drawerWidth = 240;

A következő stílust adjuk hozzá kezdőlapunkhoz:

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 });

Létrehozunk egy otthon nevű osztályt. Ennek az osztálynak API hívása lesz, hogy megkapja a felhasználó profilképét, utónevét és vezetéknevét. Emellett logikával választhatja ki, hogy melyik összetevőt jelenítse meg, akár Todo, akár Account:

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 ? : } ); } } }

Itt a kódban látni fogja, hogy authMiddleWare(this.props.history);használják. Ez a köztes szoftver ellenőrzi, hogy az authToken értéke nulla-e. Ha igen, akkor a felhasználót vissza fogja tolni a login.js. Ez azért lett hozzáadva, hogy felhasználónk /regisztráció vagy bejelentkezés nélkül nem férhet hozzá az útvonalhoz. A fájl végén adja hozzá a következő exportálást:

export default withStyles(styles)(home); 

Most arra kíváncsi, hogy mit csinál ez a kód home.js?

 {this.state.render ?  : } 

Ellenőrzi azt a renderelési állapotot, amelyet a gombra kattintva állítunk be. Hozzuk létre az összetevő könyvtárat, és e könyvtár alatt hozzunk létre két fájlt: account.jsés todo.js.

Hozzunk létre egy könyvtárat nevű util és a fájl neve auth.jsmellett a könyvtárba. Másolja be a következő kód beillesztését auth.js:

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

Egy ideig a todo.jsfájlt, csak írunk egy osztályt, amely a Helló vagyok . A következő szakaszban dolgozni fogunk a feladatainkon:

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));

Itt az ideje a fiók szakasznak. Importálja az Material felhasználói felületet, az clsx-t, az axios-t és az authmiddleWare segédprogramot a mi oldalunkra 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';

A következő stílust adjuk hozzá Fiók oldalunkhoz:

// 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' } });

Létrehozunk egy fiókkomponens nevű osztályt. Egyelőre csak másolja be a következő kódot:

// 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}  

A fájl végén adja hozzá a következő exportálást:

export default withStyles(styles)(account); 

Az account.jsvan sok használt alkatrészek. Először nézzük meg, hogyan néz ki az alkalmazásunk. Ezután elmagyarázom az összes használt alkatrészt és miért használják őket.

Lépjen a böngészőbe, és ha lejárt a tokenje, akkor átirányít az   loginoldalra. Adja meg adatait és jelentkezzen be újra. Miután ezt megtette, lépjen a Fiók fülre, és megtalálja a következő felhasználói felületet:

A Fiók részben 3 kezelő van:

  1. componentWillMount : Ez a React beépített életciklus-módszere. Az adatok betöltésére használjuk a render életciklusa előtt, és frissítjük az állapotértékeinket.
  2. ProfilePictureUpdate: Ez az az egyedi kezelőnk, amelyet használunk, így amikor a felhasználó rákattint a Fotó feltöltése gombra, elküldi az adatokat egy szerverre, és újratölti az oldalt, hogy megjelenjen a felhasználó új profilképe.
  3. updateFormValues: Ez az egyedi kezelőnk is a Felhasználó adatainak frissítéséhez. Itt a felhasználó frissítheti keresztnevét, vezetéknevét és országát. Nem engedélyezzük az e-mail és a felhasználónév frissítését, mert a háttérprogram logikája ezeken a kulcsokon múlik.

Ezen a 3 kezelőn kívül ez egy űrlap, amelynek tetején stílus található. Itt van a könyvtár struktúra a nézet mappában ezen a ponton:

+-- 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

Ezzel elkészült a Számla Irányítópultunk. Most menjen el kávézni, tartson egy kis szünetet, és a következő részben megépítjük a Todo műszerfalat.

4. szakasz: Todo műszerfal

Ebbenszakasz , mi fog fejlődni az UI ezeket a funkciókat a Todos Dashboard:

  1. Todo hozzáadása:
  2. Minden feladat:
  3. Todo törlése
  4. Teendő szerkesztése
  5. Szerezzen egy kisdiát
  6. Téma alkalmazása

Az ebben a szakaszban megvalósított Todo Irányítópult-kód ezen az elkötelezettségen található.

Lépjen todos.jsa komponens könyvtárba. Adja hozzá a következő importot a meglévő importhoz:

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';

A következő CSS elemeket hozzá kell adnunk a meglévő stíluselemekhez is:

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] } });

Hozzáadjuk az átmenetet a felugró párbeszédpanelhez:

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

Távolítsa el a meglévő todo osztályt, és másolja be a következő osztályt:

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}       ); } } }

A fájl végén adja hozzá a következő exportálást:

export default withStyles(styles)(todo); 

Először meg fogjuk érteni a felhasználói felületünk működését, majd megértjük a kódot. Lépjen a böngészőbe, és megkapja a következő felhasználói felületet:

Kattintson a Hozzáadás gombra a jobb alsó sarokban, és a következő képernyőt kapja:

Adja hozzá a Todo címet és részleteket, majd nyomja meg az elküldés gombot. A következő képernyőt kapja:

Ezt követően kattintson a nézet gombra, és láthatja a Todo teljes részleteit:

Kattintson a Szerkesztés gombra, és szerkesztheti a témát:

Kattintson a törlés gombra, és törölheti a Todo-t. Most, hogy tisztában vagyunk az Irányítópult működésével, megértjük a benne használt összetevőket.

1. Add Todo: A addo toto végrehajtásához az Material UI Dialogue komponensét fogjuk használni. Ez az alkatrész egy kampós funkciót valósít meg. Az osztályokat használjuk, ezért eltávolítjuk ezt a funkciót.

// 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 }); };

Ezen kívül megváltoztatjuk az Add Todo gomb elhelyezését is.

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

Most a lista címkét egy űrlappal helyettesítjük ebben a párbeszédben. Ez segít nekünk az új játék hozzáadásában.

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

AhandleSubmitaz buttonTypeállapot leolvasására szolgáló logikából áll . Ha az állapot üres karakterlánc, (“”)akkor közzéteszi az Add Todo API-t. Ha az állapot egy Editakkor, akkor abban a forgatókönyvben frissíti a Todo szerkesztését.

2. Get Todos: A használni kívánt todók megjelenítéséhez Grid containerés a belsejében elhelyezzük a Grid item. Ezen belül egy Cardkomponenst fogunk használni az adatok megjelenítéséhez.

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

A térkép segítségével megjelenítjük a todo elemet, miközben az API elküldi őket egy listában. A komponensWillMount életciklus segítségével fogjuk megadni és beállítani a render végrehajtása előtti állapotot. Három gomb van ( megtekintés, szerkesztés és törlés ), így 3 kezelőre lesz szükségünk a művelet kezeléséhez, amikor a gombra kattintunk. Megismerjük ezeket a gombokat a megfelelő alfejezetekben.

3. Todo szerkesztése: A todo szerkesztéséhez újból felhasználjuk a párbeszédpanel előugró kódját, amelyet a toto hozzáadásához használunk. A gomb kattintások megkülönböztetéséhez buttonTypeállapotot használunk . Az Add Todo esetében az   buttonTypeállapot (“”)a szerkesztésé Edit.

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

A handleSubmitmódszerben leolvassuk az buttonTypeállapotot, majd ennek megfelelően elküldjük a kérést.

4. Todo törlése: Ha erre a gombra kattintunk, elküldjük a todo objektumot a deleteTodoHandler-nek, majd továbbküldi a kérést a háttérprogramnak.

 this.deleteTodoHandler({ todo })}>Delete

5. A Todo megtekintése: Az adatok megjelenítésekor megcsonkítottuk őket, hogy a felhasználó bepillantást nyerjen a todo-ba. De ha egy felhasználó többet szeretne tudni róla, akkor kattintson a nézet gombra.

Ehhez a Testreszabott párbeszédet fogjuk használni. Ezen belül a DialogTitle és a DialogContent programokat használjuk. Megjeleníti a címünket és a tartalmunkat. A DialougeContent alkalmazásban az űrlapot használjuk a felhasználó által közzétett tartalom megjelenítésére. (Ez az egyik megoldás, amelyet soknak találtam, és szabadon kipróbálhat másokat.)

// 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. Téma alkalmazása: Ez az alkalmazásunk utolsó lépése. Alkalmazunk egy témát az alkalmazásunkon. Erre mi használ createMuiTheme, és ThemeProvideraz anyagi UI. Másolja be a következő kód beillesztését 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.  ); }

Hiányzott egy téma alkalmazása a gombunkra todo.jsa CardActions. Adja hozzá a színcímkét a nézet, szerkesztés és törlés gombhoz.

Lépjen a böngészőbe, és meg fogja találni, hogy minden ugyanaz, kivéve, hogy az alkalmazás más színű.

És készen vagyunk! A ReactJS és a Firebase segítségével létrehoztunk egy TodoApp alkalmazást. Ha egészen idáig felépítetted, akkor nagyon gratulálok neked ehhez az eredményhez.

Lépjen kapcsolatba velem a Twitteren és a Github-on.