Prerequisites: All past steps
Acum ca avem un endpoint configurat, il putem conecta la o interfata pentru utilizatorii de pe internet.
1. Setups:
In folderul /js adaugam folderul /components, pe acelasi nivel cu folderul /utils
In folderul /components cream fisierele MainPage.jsx si InsertPage.jsx si initializam un function component pt fiecare
Copy // js/components/MainPage.jsx
export default function MainPage () {
return (
< div ></ div >
)
}
Copy // js/components/InsertPage.jsx
export default function InsertPage () {
return (
< div ></ div >
)
}
In folderul /pages, vom modifica index.js si vom adauga componenta insert.jsx. In ele vom importa componentele definite mai sus pentru a fi desenate in pagina pe rutele /, respectiv /insert din aplicatia noastra web
Copy // pages/index.js
import MainPage from "@/js/components/MainPage" ;
export default function Home () {
return (
< MainPage />
)
}
Copy // pages/insert.js
import InsertPage from "@/js/components/InsertPage" ;
export default function Insert () {
return (
< InsertPage />
)
}
In fisierul tailwind.config.js mai adaugam o linie ('./js/components/**/*.{js,ts,jsx,tsx}') in content
Copy // tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
'./pages/**/*.{js,ts,jsx,tsx,mdx}',
'./components/**/*.{js,ts,jsx,tsx,mdx}',
'./app/**/*.{js,ts,jsx,tsx,mdx}',
'./js/components/**/*.{js,ts,jsx,tsx}'
],
.........
}
2. Pagina principala
Ca exemplu, vom construi o aplicatie care afiseaza curiozitati pe pagina principala (index). Curiozitatile sunt stocate in baza de date din cloud. Pe pagina /insert, utilizatorii pot introduce curiozitati in baza de date prin intermediul unui formular.
Pentru a adauga functionalitati si a stiliza pagina principala, accesam componenta MainPage - MainPage.jsx
Pentru ca lista de curiozitati va fi adusa asincron din baza de date, definim un state gol in function component
Accesam API-ul creat anterior si aducem curiozitatile atunci cand un utilizator acceseaza pagina
Copy // js/components/MainPage.jsx
import {useEffect , useState} from "react" ;
export default function MainPage () {
const [ records , setRecords ] = useState ([]);
useEffect (() => {
try {
fetch ( '/api/records' , {
method : 'GET' ,
})
.then (response => response .json ())
.then (json => setRecords ( json .data));
}
catch (error) {
console .log (error);
}
} , []);
return (
< div ></ div >
)
}
Adaugam componente vizuale stilizate cu tailwind si afisam fiecare curiozitate folosind functia map.
Adaugam si un buton prin care sa stergem o inregistrare din baza de date la click + functionalitatea aferenta
Copy // js/components/MainPage.jsx
import {useEffect , useState} from "react" ;
export default function MainPage () {
...... .
const deleteRecord = (event) => {
event .preventDefault ();
const id = event . target .id;
try {
fetch ( `/api/records?id= ${ id } ` , {
method : 'DELETE' ,
})
.then (response => response .json ())
.then (json => {
setRecords ( records .filter (record => record ._id !== id));
});
}
catch (error) {
console .log (error);
}
}
return (
< section className = "bg-white dark:bg-gray-900" >
< div className = "container px-6 py-10 mx-auto" >
< h1 className = "w-[500px] mx-auto text-center text-6xl" >Fun facts app</ h1 >
< p className = "w-[1000px] mx-auto text-center mt-4 text-3xl" >This is an app that showcases fun facts</ p >
< div className = "grid grid-cols-1 gap-8 mt-8 xl:mt-12 xl:gap-12 sm:grid-cols-2 xl:grid-cols-4 lg:grid-cols-3" >
{ records .map (record => (
< div
key = { record ._id}
className = "block max-w-sm p-6 bg-white border border-gray-200 rounded-lg shadow hover:bg-gray-100 dark:bg-gray-800 dark:border-gray-700 dark:hover:bg-gray-700" >
< h5 className = "mb-2 text-2xl font-bold tracking-tight text-gray-900 dark:text-white" >
{ record .title}
</ h5 >
< p className = "font-normal text-gray-700 dark:text-gray-400" >
{ record .description}
</ p >
< div className = { "flex justify-center mt-4" }>
< button type = "button"
id = { record ._id}
onClick = {deleteRecord}
className = "focus:outline-none text-white bg-red-700 hover:bg-red-800 focus:ring-4 focus:ring-red-300 font-medium rounded-lg text-sm px-5 py-2.5 mr-2 mb-2 dark:bg-red-600 dark:hover:bg-red-700 dark:focus:ring-red-900" >Delete
</ button >
</ div >
</ div >
))}
</ div >
</ div >
</ section >
)
}
La final, componenta are urmatorul cod:
Copy // js/components/MainPage.jsx
import {useEffect , useState} from "react" ;
export default function MainPage () {
const [ records , setRecords ] = useState ([]);
useEffect (() => {
try {
fetch ( '/api/records' , {
method : 'GET' ,
})
.then (response => response .json ())
.then (json => setRecords ( json .data));
}
catch (error) {
console .log (error);
}
} , []);
const deleteRecord = (event) => {
event .preventDefault ();
const id = event . target .id;
try {
fetch ( `/api/records?id= ${ id } ` , {
method : 'DELETE' ,
})
.then (response => response .json ())
.then (json => {
setRecords ( records .filter (record => record ._id !== id));
});
}
catch (error) {
console .log (error);
}
}
return (
< section className = "bg-white dark:bg-gray-900" >
< div className = "container px-6 py-10 mx-auto" >
< h1 className = "w-[500px] mx-auto text-center text-6xl" >Fun facts app</ h1 >
< p className = "w-[1000px] mx-auto text-center mt-4 text-3xl" >This is an app that showcases fun facts</ p >
< div className = "grid grid-cols-1 gap-8 mt-8 xl:mt-12 xl:gap-12 sm:grid-cols-2 xl:grid-cols-4 lg:grid-cols-3" >
{ records .map (record => (
< div
key = { record ._id}
className = "block max-w-sm p-6 bg-white border border-gray-200 rounded-lg shadow hover:bg-gray-100 dark:bg-gray-800 dark:border-gray-700 dark:hover:bg-gray-700" >
< h5 className = "mb-2 text-2xl font-bold tracking-tight text-gray-900 dark:text-white" >
{ record .title}
</ h5 >
< p className = "font-normal text-gray-700 dark:text-gray-400" >
{ record .description}
</ p >
< div className = { "flex justify-center mt-4" }>
< button type = "button"
id = { record ._id}
onClick = {deleteRecord}
className = "focus:outline-none text-white bg-red-700 hover:bg-red-800 focus:ring-4 focus:ring-red-300 font-medium rounded-lg text-sm px-5 py-2.5 mr-2 mb-2 dark:bg-red-600 dark:hover:bg-red-700 dark:focus:ring-red-900" >Delete
</ button >
</ div >
</ div >
))}
</ div >
</ div >
</ section >
)
}
Aplicatia arata acum astfel (dupa ce am introdus manual cateva date in BD):
3. Pagina /insert
In componenta InsertPage introducem un formular cu 2 campuri si un buton de submit
Copy // js/components/InsertPage.jsx
export default function InsertPage () {
return (
< section className = "bg-white dark:bg-gray-900" >
< div className = "container px-6 py-10 mx-auto" >
< h1 className = "w-[500px] mx-auto text-center text-6xl" >Fun facts app</ h1 >
< p className = "w-[1000px] mx-auto text-center mt-4 text-3xl" >This is an app that showcases fun facts</ p >
< form >
< div className = "mb-6" >
< label htmlFor = "title" className = "block mb-2 text-sm font-medium text-gray-900 dark:text-white" >Fact title</ label >
< input type = "text" id = "title"
className = "bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
placeholder = "name@flowbite.com" required />
</ div >
< div className = "mb-6" >
< label htmlFor = "description"
className = "block mb-2 text-sm font-medium text-gray-900 dark:text-white" >Fact description</ label >
< textarea id = "description"
className = "bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
required />
</ div >
< button type = "submit"
onClick = { insertRecord }
className = "text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm w-full sm:w-auto px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800" >Submit
</ button >
</ form >
</ div >
</ section >
)
}
Introducem logica de introducere a datelor la click pe butonul submit
La final, componenta InsertPage contine urmatorul cod:
Copy // js/components/InsertPage.jsx
export default function InsertPage () {
const insertRecord = (event) => {
event .preventDefault ();
const title = document .getElementById ( "title" ).value;
const description = document .getElementById ( "description" ).value;
const data = {title , description};
fetch ( "/api/records" , {
method : "POST" ,
headers : {
"Content-Type" : "application/json" ,
} ,
body : JSON .stringify (data) ,
}) .then (() => {
console .log ( "New record inserted" );
document .getElementById ( "title" ).value = "" ;
document .getElementById ( "description" ).value = "" ;
});
}
return (
< section className = "bg-white dark:bg-gray-900" >
< div className = "container px-6 py-10 mx-auto" >
< h1 className = "w-[500px] mx-auto text-center text-6xl" >Fun facts app</ h1 >
< p className = "w-[1000px] mx-auto text-center mt-4 text-3xl" >This is an app that showcases fun facts</ p >
< form >
< div className = "mb-6" >
< label htmlFor = "title" className = "block mb-2 text-sm font-medium text-gray-900 dark:text-white" >Fact title</ label >
< input type = "text" id = "title"
className = "bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
placeholder = "name@flowbite.com" required />
</ div >
< div className = "mb-6" >
< label htmlFor = "description"
className = "block mb-2 text-sm font-medium text-gray-900 dark:text-white" >Fact description</ label >
< textarea id = "description"
className = "bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
required />
</ div >
< button type = "submit"
onClick = { insertRecord }
className = "text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm w-full sm:w-auto px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800" >Submit
</ button >
</ form >
</ div >
</ section >
)
}
Pagina /insert arata acum astfel:
Trimitem totul in repository-ul remote git.
Acum ca avem o aplicatie functionala, o putem lansa pe internet folosing un serviciu in cloud!