Paso a paso como crear un CRUD con React.Js y Firebase [Toturial] [React] [Firebase]

in OCD5 years ago

17_31_33blg.png

En el día de hoy vamos a crear el típico CRUD (Empleados) con tecnología front React.js  y backend con Firebase, una base de datos en tiempo real, gratuita.


Para empezar ingresamos a la web oficial de Firebase https://firebase.google.com/   para empezar a utilizar de las bases de datos en tiempo real solo es necesario tu cuenta de Gmail.


Vamos a Ir a consola > Agregar Proyecto > Introduce el nombre de tu proyecto >  Crear Proyecto > Continuar

Agregar Firebase a tu app

Firebase React


Ingresa el nombre de la App

Seguido te mostrará un script que iremos a utilizar mas adelante. 



Del script que nos han dado nada mas vamos a utilizar esta parte 


Copiala en algún block de notas que lo vamos a utiliza mas tarde.


Requisitos para empezar: 


Tener Node >= 8.10 y npm >= 5.6 instalados en tu máquina


Vamos a empezar con abrir la terminal [Tecla Window + R] y escribir lo siguiente:


cd desktop
npx create-react-app my-app


Esto tomará algo de tiempo una vez ya este listo procedemos a abrir nuestro editor de código favorito, en mi caso estaré utilizando Visual Studio Code


Adicionalmente vamos a instalar algunos módulos que necesitamos: firebase y materialize que lo vamos a usar como framework css


npm i firebase @material-ui/core


Bueno con esto estamos listos para empezar a codear.

Vamos a la carpeta Public y dejamos nada mas el index.html que lo dejaremos de esta manera:



<!DOCTYPE html>
<html lang="en">
<head> 
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
  <l ink rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500&display=swap" />
  <l ink rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
  <title>CRUD ReactJs y Firebase :: TupaginaOnline</title>
</head>
<body>
  <noscript>You need to enable JavaScript to run this app.</noscript>
  <div id="root"></div>
</body>
</html>


Dentro de src/

Editamos el archivo index.js y lo dejaremos de esta manera:


import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
ReactDOM.render(<App />, document.getElementById("root"));


Ahora Abrimos el archivo App.js y lo dejamos así:


import React from 'react';
import './App.css';
import { BrowserRouter as Router, Route } from 'react-router-dom';
import Home from './components/Home';
import Header from './components/Header';
function App() {
  return ( 
    <Router>
       <Header />
      <Route exact path="/" component={Home} />
    </Router> 
  );
} 
export default App;


Crearemos una carpeta dentro de src/  llamada

components 

dentro de components creamos 3 archivos llamados:

- DataRecords.js

-Header.js

-Home.js

Abrimos Header.js y escribiremos lo siguiente:

import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import AppBar from '@material-ui/core/AppBar';
import Toolbar from '@material-ui/core/Toolbar';
import Typography from '@material-ui/core/Typography';
const useStyles = makeStyles({
  root: {flexGrow: 1},
});
export default function SimpleAppBar(){
  const classes = useStyles();
    return(
            <div className={classes.root}> 
                <AppBar position="static" color="default">
                    <Toolbar>
                        <Typography variant="h6" color="inherit"> CRUD ReactJs y Firebase :: TupaginaOnline >/Typography>
                    </Toolbar>
                </AppBar>
            </div>
    );
}


Ahora es el turno de Home.js:

Vamos primero con las importaciones:

import React from 'react';
import Grid from '@material-ui/core/Grid';
import Typography from '@material-ui/core/Typography';
import TextField from '@material-ui/core/TextField';
import FormControlLabel from '@material-ui/core/FormControlLabel';
import Checkbox from '@material-ui/core/Checkbox';
import Container from '@material-ui/core/Container';
import Button from '@material-ui/core/Button';
import Dialog from '@material-ui/core/Dialog';
import DialogActions from '@material-ui/core/DialogActions';
import DialogTitle from '@material-ui/core/DialogTitle';
import InputLabel from '@material-ui/core/InputLabel';
import MenuItem from '@material-ui/core/MenuItem';
import Select from '@material-ui/core/Select';
import Radio from '@material-ui/core/Radio';
import RadioGroup from '@material-ui/core/RadioGroup';
import FormControl from '@material-ui/core/FormControl';
import FormLabel from '@material-ui/core/FormLabel';
import DataRecords from './DataRecords'
import * as firebase from "firebase/app";
import "firebase/database";


Te recuerdas que copiaras parte del script que nos había dado firebase?, es momento de usarlo acá


var firebaseConfig = {
apiKey: "AIzaSy***********",
authDomain: "formreactjsfirebase.firebaseapp.com",
databaseURL: "https://formreactjsfirebase.firebaseio.com",
projectId: "formreactjsfirebase",
storageBucket: "",
messagingSenderId: "859733713828",
appId: "1:859733713828:web:28d02708c92a94ac"
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);


Creamos la clase con el siguiente contenido:

class Home extends React.Component {
state = {
employee: { id: '', basic: { name: '', email: '', address: '', phone: '', gender: '', birthdate: '' }
,job: { title: '',salary: ''},status: false},
employees: [],
        open: false,
        setOpen: false,
        nodata: 
        false,
        titleButton: 'Guardar'
}
componentDidMount() {
        this.cargarData();
}
cargarData() {
firebase.database().ref('frm01/').on('value', snapshot => {
            const data =  snapshot.val();
            if (data != null) {
                this.setState({ employees: data });
            } else {
                this.setState({ nodata: true });
            }
        });
}
onSubmit = e => {
       e.preventDefault();
       const { employee } = this.state;
       const id = employee.id === '' ? this.state.employees.length :  employee.id;
        var newEmployee = {
                 employee: {
                            basic: { name: employee.basic.name, email:  employee.basic.email, address: employee.basic.address,
                      phone:  employee.basic.phone, gender: employee.basic.gender, birthdate: employee.basic.birthdate
                    },
                    job: { title: employee.job.title, salary: employee.job.salary
                    },
                    id,
                    status: employee.status
                }
            } 
firebase.database().ref('frm01/' + newEmployee.employee.id).set(newEmployee);
this.setState(prevState => ({ open: true, setOpen: true, nodata: false, titleButton: 'Guardar', employee: {...prevState.employee, id: ''  , basic: { ...prevState.employee.basic, name: '', phone: '', birthdate: '',email: '', gender: '', address: '' }, job: { ...prevState.employee.job,  title: '', salary: ''   } } }))
}
handleDelete = (id) => { firebase.database().ref('frm01/' + id).remove();
  this.setState({ setOpen: true, open: true });
}
    handleEdit = (id) => {
        firebase.database().ref('frm01/' + id).on('value', snapshot => {
            const data = snapshot.val();
           this.setState({ employee: data.employee, titleButton: 'Editar' });
        }); 
    }
   onChange = (e) => { const { name, value } = e.target;
        this.setState({ employee: { ...this.state.employee, basic: {...this.state.employee.basic, [name]: value } } });
    }
onChangeJob = (e) => {
        const { name,value } = e.target;
this.setState({ employee: { ...this.state.employee, job: {...this.state.employee.job, [name]: value } } });
}
    handleClose = () => {this.setState({open: false, setOpen: false });}
    createYears = () => {let table = [];let options = [];
            for (let i = 1945 ; i< 2020 ; i++){options.push(`<MenuItem value="${i}">${i}</MenuItem>`);
    }
    table.push(options);
    return table;
}
    render() {
        return (
            <React.Fragment>
                <Container maxWidth="lg" style={{ paddingTop: "50px" }}>
                    <Grid container spacing={3}>
                    <Grid item xs={12} sm={6} >
                         <Typography variant="h6" gutterBottom>
                                Rellene los campos
        </Typography>
            <form onSubmit={this.onSubmit}>
                                <Grid container spacing={3}>
                                    <Grid item xs={12} sm={12}>
                                        <TextField onChange={this.onChange} required id="name" name="name" label="Nombre Completo" fullWidth value={this.state.employee.basic.name} />
                                    </Grid>
            <Grid item xs={12} sm={6}>
                                        <TextField onChange= {this.onChange} required id="email" name="email" label="Email" type="email" fullWidth value={this.state.employee.basic.email} />
                                    </Grid>
           <Grid item xs={12} sm={6}>
                                        <TextField onChange= {this.onChange} required id="phone" name="phone" label="Teléfono" fullWidth value={this.state.employee.basic.phone} />
                  </Grid>
                                    <Grid item xs={12}> 
                       <TextField onChange={this.onChange} required id="address" name="address" label="Dirección" fullWidth value={this.state.employee.basic.address} />
                                    </Grid>
                <Grid item xs={12} sm={6}>
                                        <InputLabel  htmlFor="birthdate">Fecha Nacimiento</InputLabel>
                                         <TextField onChange={this.onChange} required id="birthdate" name="birthdate" format="yyyy-mm-dd" type="date" fullWidth value={this.state.employee.basic.birthdate} />
 </Grid>    
 <Grid item xs={12} sm={6}>
                                        <FormControl  component="fieldset" >
                                            <FormLabel  component="legend">Genero</FormLabel>
                                            <RadioGroup aria-label="gender" name="gender" value={this.state.employee.basic.gender} onChange={this.onChange} >
                                                <FormControlLabel value="femenino" control={<Radio />} label="Femenino" />
                                                <FormControlLabel value="masculino" control={<Radio />} label="Masculino" /> 
  </RadioGroup>
                                        </FormControl> 
        </Grid> 
                                    <Grid item xs={12} sm={6}> 
                    <InputLabel htmlFor="title">Cargo a desempeñar</InputLabel> 
                      <Select name="title" fullWidth value={this.state.employee.job.title} onChange={this.onChangeJob} inputProps={{ name: 'title', id: 'title', }} > 
                  <MenuItem value={'Programador'}> Programador </MenuItem>
                      <MenuItem value={'Diseñador'}> Diseñador </MenuItem>
                        <MenuItem value={'Community Manager'}> Community Manager </MenuItem>
          </Select>
                                    </Grid> 
                      <Grid item xs={12} sm={6}>
                                        <TextField onChange={this.onChangeJob} required id="salary" name="salary" label="Salario pretendido" fullWidth value={this.state.employee.job.salary} />
                                    </Grid>
 <Grid item xs= {12}> <FormControlLabel control={<Checkbox required color="secondary" name="saveAddress" value="yes" />} label="Aceptar los términos y condiciones" />
                                    </Grid>
                                    <Button variant="contained" color="primary" type="submit" > {this.state.titleButton}
                                    </Button>
 </Grid>
                            </form>
                        </Grid>
          <Grid item xs={12} sm={6} style={{ backgroundColor: "#f5f5f5" }}>
 <Typography variant="h6" gutterBottom> Registros </Typography>
 <DataRecords  handleEdit={this.handleEdit} handleDelete={this.handleDelete} Nodata={this.state.nodata} Employees={this.state.employees} /> 
                        </Grid> 
                    </Grid> 
               </Container> 
                <Dialog open={this.state.open} onClose={this.handleClose} aria-labelledby="alert-dialog-title" aria-describedby="alert-dialog-description"
                >
                    <DialogTitle  id="alert-dialog-title">{"Se ha procesado satisfactoriamente."}</DialogTitle>
 <DialogActions>
                    <Button onClick={this.handleClose} color="primary"> Cerrar </Button> </DialogActions>
                </Dialog>
            </React.Fragment>
        )
    }
}
export default Home;


Ahora vamos con el último archivo de nuestro ejemplo crud, el archivo DataRecords.js



import React, { Component } 
from 'react'
import Table from '@material-ui/core/Table';
import TableBody from '@material-ui/core/TableBody';
import TableCell from '@material-ui/core/TableCell';
import TableHead from '@material-ui/core/TableHead';
import TableRow from '@material-ui/core/TableRow';
import Button from '@material-ui/core/Button';
class DataRecords extends
Component {
    render() {
        return (
            <Table>
                <TableHead>
           <TableRow>
<TableCell align="left">Nombres</TableCell>
<TableCell align="left">Email</TableCell>
<TableCell  align="right">Acciones</TableCell>
 </TableRow>
</TableHead>
                <TableBody>
                    {!this.props.Nodata ? this.props.Employees.map(row => {
 const { employee } = row;
return (
        <TableRow key={employee.id}>
        <TableCell component="th" scope="row">
         {employee.basic.name}
        </TableCell>
<TableCell align="left">{employee.basic.email}</TableCell>
<TableCell align="right">
<Button size="small" variant="outlined" color="primary" onClick={() => this.props.handleEdit(employee.id)}>
                  Ver/Editar </Button>
<Button style={{ marginLeft: "10px" }} size="small" variant="outlined" color="secondary" onClick={() => this.props.handleDelete(employee.id)}  Eliminar </Button>
</TableCell> 
</TableRow>
 )
 }) : 'No Data' }
 </TableBody>
 </Table> 
 )
    }
}
export default DataRecords;


Salimos de la carpeta components y abrimos el archivo App.css y lo editamos de esta manera:



.App { text-align: center;
}
.App-logo {
animation: App-logo-spin infinite 20s linear;
  height: 40vmin;
  pointer-events: none;
}
.App-header {
    background-color: #282c34;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    font-size: calc(10px + 2vmin);
    color: white;
}
.App-link {
    color:  #61dafb;
}
@keyframes App-logo-spin {
  from {
        transform: rotate(0deg);
  }
  to {
        transform: rotate (360deg);
  }
}


Procedemos a ejecutar en nuestro Terminal integrado de VisualStudioCode  el siguiente comando:

npm run build


Se habrá generado una carpeta llamada build dentro de nuestro proyecto. el contenido de la misma es el que subiremos a nuestro Hosting.


Podemos ver el ejemplo en vivo en el siguiente Link: https://reactfirebasetest.tupaginaonline.net/


acá una captura Final:


https://tupaginaonline.net/archivos/arc16_57_51.png






Si deseas tener tu página web, dale clic al botón de

abajo


¡Ordena ya tu página web!