/DEVinHouse_CRUD

CRUD desenvolvido com React, Hooks e Material-UI

Primary LanguageJavaScriptMIT LicenseMIT

DEVinHouse_CRUD

CRUD desenvolvido pelos alunos do curso DEVinHouse para revisão dos assuntos das 5 primeiras semanas.


PASSO A PASSO


Instalar Nodejs


  • Verificar se tem node instalado

    node -v

  • Instalar node na versão mais atual LTS (em 18 de dezembro de 2020 seria a 14)

Criar projeto React


  • Na pasta que desejamos, criar o projeto:

    npx create-react-app crud

  • Abrir o projeto no seu editor preferido (indico o Visual Studio Code):

    code crud

  • Abrir um terminal e rodar a aplicação:

    npm start

    OBS: Em geral ele irá renderizar a aplicação na porta 3000 (http://localhost:3000)


Instalar Material-UI


Para agilizar o desenvolvimento e garantir a consistência do design, indico o uso de uma biblioteca de componentes desenvolvida para o React com base no Material Design (do Google 😉)

Visite o site do Material-UI para seguir as instruções de instalação e conhecer os componentes... esse site deve permanecer aberto durante todo o desenvolvimento do projeto para consultas: (https://material-ui.com/pt/)

  • Instale as bibliotecas de componentes e ícones:

    npm install @material-ui/core @material-ui/icons

  • No projeto, entre na pasta public, e dentro do arquivo arquivo index.html, dentro do head carregue a fonte necessária para o Material, a Roboto:

    <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" />
    

Agora sim, #partiu DESENVOLVIMENTO


Antes de criarmos nossos códigos, vamos "limpar" a aplicação, removendo conteúdos desnecessários:

  • em App.js, apague as importações da logo e do App.css e todo o conteúdo dentro do return, substituindo-o por uma div vazia.
  • apague os arquivos logo.svg e App.css.

Em src vamos criar uma pasta pages, onde incluiremos as páginas da nossa aplicação.

  • Nesse projeto, em especial, haverá apenas uma página, a Home

Em PAGES criaremos a pasta Home:

index.js

import { Box, Grid, Typography } from "@material-ui/core";

function Home() {
  return (
    <Box m={4}>
      <Typography variant="h2" component="h1" align="center" gutterBottom color="textSecondary">
        CRUD dos DEVinHouse
      </Typography>

      <Grid container spacing={2}>
        <Grid item xs={12} sm={4}>
          {/* Aqui vai nosso cadastro */}
        </Grid>

        <Grid item xs={12} sm={8}>
          {/* Aqui vai nossa listagem */}
        </Grid>
      </Grid>
    </Box>
  );
}

export default Home;

Para organizar nosso código, em src vamos criar uma pasta containers, onde incluiremos partes do código que são grandes, mas não o suficiente para ser uma página.

  • Nesse projeto haverá 2 containers: Cadastro e Listagem.

Em CONTAINERS criaremos a pasta Cadastro:

index.js

import "./index.css";
import { Box, Paper, Typography, TextField, Button } from "@material-ui/core";

function Cadastro() {
  return (
    <Box component={Paper} p={2}>
      <Typography variant="h4" component="h2" gutterBottom color="primary">
        Cadastro
      </Typography>
      <Box component="form">
        <TextField variant="outlined" size="small" label="Nome" fullWidth margin="dense"/>
        <TextField variant="outlined" size="small" label="Sobrenome" fullWidth margin="dense"/>
        <Box className="button-wrapper">
          <Button variant="contained" color="primary">Salvar</Button>
        </Box>
      </Box>
    </Box>
  );
}

export default Cadastro;

index.css

.button-wrapper{
  display: flex;
  justify-content: center;
  padding: 10px 0 0;
}

OBS: Por enquanto não nos preocupamos com a lógica, mas tão somente com a parte visual da aplicação.


Em CONTAINERS criaremos também a pasta Listagem:

index.js

import "./index.css";
import { Box, Paper, Typography, Button, Table, TableHead, TableBody, TableRow, TableCell } from "@material-ui/core";
import { Edit, Delete } from "@material-ui/icons";

// vamos criar uma linha, apenas para visualizar a renderização na tela
const linhas = [{ id: 1, nome: "Fulana", sobrenome: "de Tal" }];

function Listagem() {
  return (
    <Box component={Paper} p={2}>
      <Typography variant="h4" component="h2" gutterBottom color="primary">
        Listagem
      </Typography>
      <Table>
        <TableHead>
          <TableRow>
            <TableCell align="center">NOME</TableCell>
            <TableCell align="center">SOBRENOME</TableCell>
            <TableCell></TableCell>
          </TableRow>
        </TableHead>
        <TableBody>
          {linhas.map((linha) => (
            <TableRow key={linha.id}>
              <TableCell align="center">{linha.nome}</TableCell>
              <TableCell align="center">{linha.sobrenome}</TableCell>
              <TableCell align="center">
                <Button variant="contained" color="primary" style={{ marginRight: "10px" }} startIcon={<Edit />}>
                  Editar
                </Button>
                <Button variant="contained" color="secondary" startIcon={<Delete />}>
                  Deletar
                </Button>
              </TableCell>
            </TableRow>
          ))}
        </TableBody>
      </Table>
    </Box>
  );
}

export default Listagem;

Esse é o resultado da nossa aplicação até o momento:

crud

Vamos "dar vida" a essa aplicação :neckbeard:


Como não estamos usando Redux ou qualquer estrutura de gerenciamento "global de estados", prefiro colocar nosso estado no componente pai, que no nosso caso é a página Home, e ir mandando pros filhos as props que eles precisam... vamos lá.


Em scr/pages/Home/index.js, teremos:

import { useState } from "react";
import { Box, Grid, Typography } from "@material-ui/core";

import Cadastro from "../../containers/Cadastro";
import Listagem from "../../containers/Listagem";

function Home() {
  const [pessoa, setPessoa] = useState({ nome: "", sobrenome: "" });
  const [pessoas, setPessoas] = useState([]);

  return (
    <Box m={4}>
      <Typography variant="h2" component="h1" align="center" gutterBottom color="textSecondary">
        CRUD dos DEVinHouse
      </Typography>

      <Grid container spacing={4}>
        <Grid item xs={12} sm={4}>
          <Cadastro pessoa={pessoa} setPessoa={setPessoa} pessoas={pessoas} setPessoas={setPessoas}/>
        </Grid>

        <Grid item xs={12} sm={8}>
          <Listagem setPessoa={setPessoa} pessoas={pessoas} setPessoas={setPessoas}/>
        </Grid>
      </Grid>
    </Box>
  );
}

export default Home;

Em scr/containers/Cadastro/index.js, teremos:

import "./index.css";
import { Box, Paper, Typography, TextField, Button } from "@material-ui/core";

function Cadastro(props) {
  const { pessoa, setPessoa, pessoas, setPessoas } = props;

  const handleChange = ({ name, value }) => {
    setPessoa({ ...pessoa, [name]: value });
  };

  const handleSubmit = (e) => {
    e.preventDefault();
    const pessoaNaLista = pessoas.some((item) => item.id === pessoa.id);
    if (pessoaNaLista) {
      const result = pessoas.map((item) => item.id === pessoa.id ? pessoa : item);
      setPessoas(result);
    } else {
      setPessoas([ ...pessoas, { ...pessoa, id: Math.random().toString(36).substr(2, 9) } ]);
    }
    setPessoa({ id: 0, nome: "", sobrenome: "" });
  };

  return (
    <Box component={Paper} p={2}>
      <Typography variant="h4" component="h2" gutterBottom color="primary">
        Cadastro
      </Typography>
      <Box component="form" onSubmit={handleSubmit}>
        <TextField
          required fullWidth margin="dense" variant="outlined" size="small" 
          label="Nome" name="nome" value={pessoa.nome} onChange={(e) => handleChange(e.target)}
        />
        <TextField
          required fullWidth margin="dense" variant="outlined" size="small"
          label="Sobrenome" name="sobrenome" value={pessoa.sobrenome} onChange={(e) => handleChange(e.target)}
        />
        <Box className="button-wrapper">
          <Button variant="contained" color="primary" type="submit">
            Salvar
          </Button>
        </Box>
      </Box>
    </Box>
  );
}

export default Cadastro;

Em scr/containers/Listagem/index.js, teremos:

import { Box, Paper, Typography, Button, Table, TableHead, TableBody, TableRow, TableCell } from "@material-ui/core";
import { Edit, Delete } from "@material-ui/icons";

function Listagem(props) {
  const { setPessoa, pessoas, setPessoas } = props;

  const handleEdit = (id) => {
    const pessoaClicada = pessoas.find((pessoa) => pessoa.id === id);
    setPessoa(pessoaClicada);
  };

  const handleDelete = (id) => {
    const result = pessoas.filter((pessoa) => pessoa.id !== id);
    setPessoas(result);
  };

  return (
    <Box component={Paper} p={2}>
      <Typography variant="h4" component="h2" gutterBottom color="primary">
        Listagem
      </Typography>
      <Table>
        <TableHead>
          <TableRow>
            <TableCell align="center">NOME</TableCell>
            <TableCell align="center">SOBRENOME</TableCell>
            <TableCell></TableCell>
          </TableRow>
        </TableHead>
        <TableBody>
          {pessoas.map((item) => (
            <TableRow key={item.id}>
              <TableCell align="center">{item.nome}</TableCell>
              <TableCell align="center">{item.sobrenome}</TableCell>
              <TableCell align="center">
                <Button variant="contained" color="primary" style={{ marginRight: "10px" }} startIcon={<Edit />} onClick={() => handleEdit(item.id)}>
                  Editar
                </Button>
                <Button variant="contained" color="secondary" startIcon={<Delete />} onClick={() => handleDelete(item.id)}>
                  Deletar
                </Button>
              </TableCell>
            </TableRow>
          ))}
        </TableBody>
      </Table>
    </Box>
  );
}

export default Listagem;

Finalmente, vamos expor nosso projeto na web (deploy com SURGE)


  • Primeiro "buildamos" o projeto

    npm run build
    

  • Dica: sempre criar um arquivo 202.html para poder usar subrotas

    cp build/index.html build/200.html
    

Usaremos o Surge.sh

  • Instalar o surge globalmente:

    npm install -g surge
    

  • Rodar o surge e seguir os passos solicitados no terminal:

    surge ./build
    

E o passo mais importante: Comemorar!!!


comemorar