Last Updated: 2021-03-31

(Referência)

O React é uma biblioteca JavaScript. Não é Framework, embora muitos se referem a ele assim. É importante ter um conhecimento básico da linguagem JavaScript.

Você tem basicamente dois caminhos para construir suas aplicações React:

Desenvolvimento online

Usa as bibliotecas online e um editor baseado em navegador. Vamos usar aqui o codepen.io com este código inicial

Veja as configurações necessárias para usar React no codepen.io

  1. Clique me Settings

  1. Selecione JS e Babel com JavaScript Preprocessor

  1. Na seção Add External Scripts/Pens adicione os seguintes links para as bibliotecas

https://unpkg.com/react/umd/react.development.js

https://unpkg.com/react-dom/umd/react-dom.development.js

Desenvolvimento local

Vamos usar o VSCODE, mas é possível usar qualquer ide moderna tal como: Eclipse, Intellij IDEA, etc.

  1. Instale o Node.js
  2. Vamos criar uma aplicação SPA (single-page application) usando npx. Abra o seu cmd (Windows 10) e navegue para a pasta onde será criado o projeto e digite
npx create-react-app aula

Depois de algum tempo você verá:

  1. Depois digite
c:\React>cd aula
c:\React>code .

Para abrir o vscode. Você deverá ver o seguinte

  1. Vamos testar o app. Use o atalho do teclado para abrir o terminal. No terminal digite o seguinte comando:

O Chrome irá abrir uma página usando a URL http://localhost:3000/ e a app estará rodando assim:

  1. Instale o plugin do Chrome React Developer Tools para visualizar os componentes React na página. Pressione F12.

A guia mostra os componentes raiz do React que foram renderizados na página, bem como os subcomponentes que eles acabaram renderizando. Ao selecionar um dos componentes na árvore, você pode inspecionar e editar seus adereços e estado atuais no painel à direita. Na localização atual, você pode inspecionar o componente selecionado, o componente que o criou, o componente que o criou e assim por diante.

  1. No vscode instale as extensões Babel Script (syntax highlighting) e VS Code ES7 React/Redux/React-Native/JS snippets (JavaScript and React/Redux snippets in ES7+ with Babel plugin features for VS Code).

Abra outro terminal no vscode e delete todos os arquivos da pasta src.

c) 2020 Microsoft Corporation. Todos os direitos reservados.

C:\React>cd aula

C:\React\aula>cd src

C:\React\aula\src>del *
C:\React\aula\src\*, Tem certeza (S/N)? s

C:\React\aula\src>

Crie um arquivo novo chamado index.js na pasta src e insira o código:

import ReactDOM from 'react-dom'

ReactDOM.render(
    <h1>Alô mundo!</h1>,
    document.getElementById('root')
  );

Você verá no browser

Vamos aprender agora os fundamentos das aplicações React: elementos e componentes. Mas antes, como React é uma biblioteca JavaScript, vamos fazer uma breve revisão da linguagem JavaScript.

(referência)

A principal característica da JavaScript é que as funções são objetos, permitindo às funções a capacidade para armazenar código executável e serem passadas como parâmetro para qualquer outro objeto.

Vamos usar o codepen.io para executar nossos exemplos.

Strings

São objetos e representam sequências de caracteres. Exemplos:

console.log("alo2".length);
console.log("alo2".indexOf('l'));
console.log("alo2".toUpperCase());

Estes exemplos mostram como acessar as propriedades e funções de objetos do tipo String. Observe o uso do . assim como em Java.

Variáveis

Podemos usar as palavras reservadas var, let e const para declarar variáveis. Se uma variável é definida usando var dentro de uma estrutura (por exemplo dentro de uma estrutura de controle if), ela será visível por toda a função fora da estrutura. A definição de variáveis usando o let foi introduzida no ECMAScript 6. O let permite escopo de bloco, ou seja, é possível definir uma variável em um bloco if, e esta variável ter escopo limitado ao bloco if- por exemplo. const funciona como let porém seu valor não pode ser alterado.

Estruturas de Controle

var name = "kittens";
if (name == "puppies") {
  name += "!";
} else if (name == "kittens") {
  name += "!!";
} else {
  name = "!" + name;
}
name == "kittens!!"

while (true) {
  // an infinite loop!
}


var input;
do {
  input = get_input();
} while (inputIsNotValid(input))

for (var i = 0; i < 5; i++) {
  // Will execute 5 times
}
var allowed = (age > 18) ? "yes" : "no";
switch(action) {
    case 'draw':
        drawit();
        break;
    case 'eat':
        eatit();
        break;
    default:
        donothing();
}

Objetos

Objetos JavaScript são simplesmente coleções de pares nome-valor. Como tal, eles são similares à:

As propriedades dos objetos são pares nome-valor. A parte "nome" é uma string JavaScript, enquanto a parte "valor" pode ser qualquer valor JavaScript — incluindo mais objetos. Isso permite que você construa estruturas de dados de qualquer complexidade.

Criação de objetos

Podemos criar objetos de duas maneiras:

var obj = new Object();

var obj = {};

As duas maneiras são equivalentes; a segunda forma é chamada de sintaxe de objeto literal e é mais conveniente. Essa sintaxe é também o coração do formato JSON.

Exemplos:

var pessoa = {};

//usando a notação .
pessoa.nome = "Edson";
console.log(pessoa.nome);

//usando notação de mapa associativo
pessoa["sobrenome"] = "Angoti";
console.log(pessoa["sobrenome"]);

A sintaxe de objeto literal pode ser usada para inicializar completamente um objeto:

var conta = {
    numero: 123,
    agencia: "centro",
    detalhes: {
        protegida: true,
        remunerada: false
    }
}

console.log(conta.numero)
console.log(conta["detalhes"]["protegida"])

Vetores

São objetos em JavaScript. Eles funcionam de forma muito similar à objetos regulares (propriedades numéricas podem naturalmente ser acessadas somente usando a sintaxe [], colchetes ).

Exemplos:

var a = new Array();
 a[0] = "dog";
 a[1] = "cat";
 a[2] = "hen";
console.log(a.length)

var b = ["dog", "cat", "hen"];
console.log(a.length)

Funções

Junto com objetos, funções são os componentes principais para o entendimento do JavaScript. A função mais básica não poderia ser mais simples:

function add(x, y) {
    var total = x + y;
    return total;
}

Os parâmetros podem ser acessados através de uma propriedade chamada arguments dentro da função. Esta propriedade é um vetor que contém todos os valores passados para a função.

function add() {
    var sum = 0;
    for (var i = 0, j = arguments.length; i < j; i++) {
        sum += arguments[i];
    }
    return sum;
}

console.log(add(1,2,3,4))

Classes em JavaScript

Na POO clássica, objetos encapsulam dados e métodos que operam sobre esses dados. JavaScript é uma linguagem baseada em protótipos que não contém a estrutura de classe, como tem em C++ e Java. Em vez disso, JavaScript usa funções como classes.

Exemplo

function PessoaFisica(nome, sobrenome) {
    return {
        nome: nome,
        sobrenome: sobrenome,
        nomeCompleto: function() {
            return this.nome + ' ' + this.sobrenome;
        }
    }
}

var pessoa1 = PessoaFisica("Edson", "Angoti")
console.log(pessoa1.nomeCompleto())

JSX é uma extensão que facilita escrever código HTML no React através da conversão de tags HTML em elementos React.

O exemplo a seguir cria um elemento React:

const elementoReact = <h1>Alô mundo!</h1>;

ReactDOM.render(elementoReact, document.getElementById("root"));

Elementos React são imutáveis, por isso declaramos uma variável usando a palavra reservada const.

Execute o código acima

Código javascript pode ser inserido em expressões JSX entre chaves. Veja exemplos abaixo:

function PessoaFisica(nome, sobrenome) {
  return {
    nome: nome,
    sobrenome: sobrenome,
    nomeCompleto: function () {
      return this.nome + " " + this.sobrenome;
    }
  };
}
const user = PessoaFisica("Edson", "Angoti");
const element = <h1>Hello, {user.nomeCompleto()}</h1>;
ReactDOM.render(element, document.getElementById("root"));

Atributos de elementos HTML

O React DOM usa camelCase como convenção para nomes de propriedades ao invés dos nomes de atributos do HTML. Então o atributo classname para aplicação de CSS é escrito className.

  1. Para valores literais use aspas.
  2. Para valores armazenados em objetos JavaScript use {}.
  3. Para declaração de estilo inline deve-se usar dois conjuntos de chaves {{}}.

Observe o uso de comentários dentro de um elemento JSX usando {/* comentários */}. Nomes de atributos devem seguir

Veja exemplo

Entenda um componente React como funções JavaScript que recebem um argumento chamado props e retornam elementos React que descrevem o que deve aparecer na tela. Podemos criar componentes de duas formas:

function ComponenteSaudacao(props) {
  return (
    <h1 style={{ background: "red" }}>
      Hello, {props.user.nomeCompleto()}
      <img
        src={props.imgUrl}
        width="60"
        style={{ margin: "10px 0px 0px 10px" }}
      />
    </h1>
  );
}
class ComponenteSaudacaoClass extends React.Component {
   render() {
      return (
         <h1 style={{ background: "red" }}>
            Hello, {this.props.user.nomeCompleto()}
            <img
               src={this.props.imgUrl}
               width="60"
               style={{ margin: "10px 0px 0px 10px" }}
            />
         </h1>
      );
   }
}

Depois que um componente é declarado, você pode chama-lo assim:

ReactDOM.render(
   <ComponenteSaudacaoClass user={user} imgUrl={imgUrl} />,
   document.getElementById("root")
);

Não importa como você declarou o componente, como função ou classe, a chamada é da mesma forma.

A propriedade props passada para o componente é um objeto JavaScript, e usando notação JSON pode ser representado assim:

const usuario = PessoaFisica("Edson", "Angoti");
const imagem = "https://miro.medium.com/max/3840/1*vHHBwcUFUaHWXntSnqKdCA.png";

props = { user : usuario, imgUrl : imagem }

Veja exemplo

Fonte: React documentation

O ciclo de vida de um componente React tem três categorias - Montagem, Atualização e Desmontagem.

Para o estudo do ciclo de vida vamos trabalhar com componentes definidos como classe. As propriedades da classe são imutáveis, portanto todos os valores passados para o componente através de props não podem ser alterados. Podemos usar a propriedade state que permite manter o estado do componente e sofrer alterações. Aqui mostramos o construtor do componente onde declaramos o estado do componente.

HTML
<div id="teste"></div>

Javascript
class Contador extends React.Component {
   constructor(props) {
      console.log("constructor");
      super(props);
      this.state = { contador: 1 };
   }

   componentDidMount() {
      console.log("ComponentDidMount");
   }

   componentDidUpdate() {
      console.log("componentDidUpdate");
   }
   componentWillUnmount() {}

   incrementa() {
      this.setState({ contador: ++this.state.contador });
   }

   render() {
      return (
         <div>
            <h1> teste de eventos </h1>
            <button onClick={() => this.incrementa()}>
               {this.state.contador}
            </button>
         </div>
      );
   }
}

ReactDOM.render(<Contador />, document.getElementById("teste"));

O método componentDidMount() é executado depois que o componente é renderizado no DOM.

O método componentWillUnmount() é executado sempre que o componente for removido.

Veja exemplo

Manipular eventos em elementos React é muito semelhante a manipular eventos em elementos do DOM. Existem algumas diferenças de sintaxe:

Então na função render() programamos o evento assim:

render() {
      return (
         <button onClick={()=>this.incrementaContador()}>
            {this.state.contador}
         </button>
      );
}

a função de callback que será chamada quando o evento ocorrer será incrementaContador():

incrementaContador() {
      this.setState({ contador: ++this.state.contador })
}

Observe como alteramos o valor de contador através da chamada da função setState().

O código final fica assim:

class Contador extends React.Component {
   constructor(props) {
      super(props);
      this.state = { contador: 1 };
   }

   incrementaContador() {
      this.setState({ contador: ++this.state.contador })
   }

   render() {
      return (
         <button onClick={()=>this.incrementaContador()}>
            {this.state.contador}
         </button>
      );
   }
}

ReactDOM.render(<Contador />, document.getElementById("root"));

Execute o código

Em HTML, elementos de formulário como <input>, <textarea> e <select> normalmente mantêm seu próprio estado e o atualiza baseado na entrada do usuário. Em React, o estado mutável é normalmente mantido na propriedade state dos componentes e atualizado apenas com setState().

class NameForm extends React.Component {
   constructor(props) {
      super(props);
      this.state = { value: "" };
   }

   handleChange(event) {
      this.setState({ value: event.target.value });
   }

   handleSubmit(event) {
      alert("Um nome foi enviado: " + this.state.value);
      event.preventDefault();
   }

   render() {
      return (
         <form onSubmit={(e) => this.handleSubmit(e)}>
            <label>
               Nome:
               <input
                  type="text"
                  value={this.state.value}
                  onChange={(e) => this.handleChange(e)}
               />
            </label>
            <input type="submit" value="Enviar" />
         </form>
      );
   }
}

ReactDOM.render(<NameForm />, document.getElementById("root"));

Execute

Hooks foram introduzidos em 2018 no React 16.8. Eles permitem que você use o state e outros recursos sem escrever uma classe.

Hooks são funções que permitem acesso aos recursos de state e ciclo de vida do React a partir de componentes funcionais, ou seja, escritos como funções e não como classes. Hooks não funcionam dentro de classes — eles permitem que você use React sem classes.

Para usar hooks você deve importar assim:

import React, { useEffect, useState } from 'react';

Exemplo de utilização de efeitos colaterais

import React, { useState, useEffect } from 'react';

function Exemplo() {
  const [count, setCount] = useState(0);

  // Similar ao componentDidMount e componentDidUpdate:
  useEffect(() => {
    // Atualiza o titulo do documento usando a API do browser
    document.title = `Você clicou ${count} vezes`;
  });

  return (
    <div>
      <p>Você clicou {count} vezes</p>
      <button onClick={() => setCount(count + 1)}>
        Clique aqui
      </button>
    </div>
  );
}

Execute

Para criar a aplicação:

npx create-react-app crud

Para importar o Boostrap:

C:\React\crud>npm install react-bootstrap bootstrap

Adicione a seguinte linha no topo de seu arquivo index.js

import 'bootstrap/dist/css/bootstrap.min.css';

Em sua pasta src, crie uma nova pasta chamada componentes. Esta pasta conterá todos os nossos componentes React. Na nova pasta, crie dois arquivos intitulados hoct.js e ListaProdutos.js.

Esses dois arquivos conterão os componentes que serão necessários em nosso aplicativo. O arquivo ListaProdutos.js tratará da exibição do resultado da consulta à API, e o arquivo hoc.js conterá um componente de ordem superior que exibirá uma mensagem enquanto a requisição HTTP que faremos ainda estiver em andamento. No arquivo ListaProdutos.js que criamos dentro da pasta de componentes, vamos colar o seguinte código:

import React from 'react';


const ListaProdutos = (props) => {
    const { produtos } = props;
    if (!produtos || produtos.length === 0) return <p>Carregando ...</p>;
    return (
        <TabelaDeProdutos listaDeProdutos={produtos}/>
    );
};

class Linha extends React.Component {
    render() {
        const produto = this.props.produto;

        return (
            <tr>
                <td>{produto.id}</td>
                <td>{produto.name}</td>
                <td>{produto.description}</td>
                <td>{produto.price}</td>
                <td>{produto.imgUrl}</td>
            </tr>
        );
    }
}

class TabelaDeProdutos extends React.Component {
    render() {
        const linhas = [];

        this.props.listaDeProdutos.forEach(
            (produto) => {
                linhas.push(
                    <Linha produto={produto} />
                );
            }
        );

        return (
            <table className="table">
                <thead>
                    <tr>
                        <th>ID</th>
                        <th>Nome</th>
                        <th>Descrição</th>
                        <th>Preço</th>
                        <th>Imagem</th>
                    </tr>
                </thead>
                <tbody>{linhas}</tbody>
            </table>
        );
    }
}


export default ListaProdutos;

No arquivo hoc.js que criamos dentro da pasta de componentes, vamos colar o seguinte código:

import React from 'react';

function hoc(Component) {
  return function CarregandoProdutos({ isLoading, ...props }) {
    if (!isLoading) return <Component {...props} />;
    return (
      <p style={{ textAlign: 'center', fontSize: '30px' }}>
        Carregando dados
      </p>
    );
  };
}
export default hoc;

No seu arquivo App.js dentro da pasta src, vamos colar o seguinte código:

import React, { useEffect, useState } from 'react';
import './App.css';
import ListaProdutos from './componentes/ListaProdutos';
import hoc from './componentes/hoc';

function App() {
  const CarregandoProdutos = hoc(ListaProdutos);
  const [estadoDaAplicacao, setEstadoDaAplicacao] = useState({
    consultando: false,
    produtos: null,
  });

  useEffect(() => {
    setEstadoDaAplicacao({ consultando: true });
    const apiUrl = `https://projeto-integrador-4.herokuapp.com/products`;
    fetch(apiUrl)
      .then((res) => res.json())
      .then((repos) => {
        setEstadoDaAplicacao({ consultando: false, produtos: repos.content });
      });
  }, [setEstadoDaAplicacao]);
  
  return (
    <div className='App'>
        <CarregandoProdutos isLoading={estadoDaAplicacao.consultando} produtos={estadoDaAplicacao.produtos} />
    </div>
  );
}
export default App;

Nosso App.js é um componente funcional que usa React Hooks para lidar com o estado e também os efeitos colaterais.

  1. Instalar o Debugger for Chrome

  1. Configurar o projeto

Clique no ícone de debug. Uma pasta .vscode será criada na raiz do seu projeto

  1. Edite o arquivo launch.json e modifique a propriedade "url" para apontar para o seu servidor de desenvolvimento. Se estiver usando o create-react-app, será o http://localhost:3000.
  2. Executar o debugger

Aperte o botão verde no painel de debug.

Launch Chrome against localhost

  1. Será aberta uma nova janela do Chrome e no vscode aparecerá no alto da tela a barra de controle

  1. Você pode adicionar breakpoints em alguma linha do seu código. O breakpoint é marcado com uma bola vermelha no VSCode.

Renderização condicional em React funciona da mesma forma que condicionais funcionam em JavaScript.

Operadores JavaScript como if ou o operador condicional ternário (expressão condicional ? expr1 : expr2 ) podem ser usados para criar elementos representando estados.

Exemplo

Atribuição de Elementos React a variáveis

Elementos React podem ser armazenados em variáveis, pois naturalmente Javascript permite armazenar tanto valores quanto funções.

var ola = <H1>Olá Mundo!</H1>;

Exemplo

If inline com o Operador Lógico &&

Em JavaScript, expressões como (true && expressão) são sempre avaliadas como verdade e (false && expressão) são sempre avaliadas como false.

Portanto, se a condição é true, o elemento logo depois do && irá aparecer no resultado. Se o elemento é false, React irá ignora-lo.

Exemplo

If-Else inline com Operador Condicional

Outro método para renderizar elementos inline é utilizar o operador condicional em JavaScript condição ? true : false.

Exemplo

const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map(
  (number) =><li>{number}</li>
);

  ReactDOM.render(
  <ul>{listItems}</ul>,
  document.getElementById('root')
);

O código acima mostra uma lista não ordenada na tela

Porém o console mostra um erro:

‘key' é um atributo especial que você precisa definir ao criar listas de elementos. Iremos analisar os motivos pelos quais isso é importante na próxima seção.

Este atributo deve ser um valor do string único para cada elemento da lista. Assim, o código pode se corrigido:

const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map(
  (number) =><li key={number.toString()}>{number}</li>
);

  ReactDOM.render(
  <ul>{listItems}</ul>,
  document.getElementById('root')
);

Quando não temos nenhum valor único para os itens renderizados, podemos usar o índice do item como chave em último recurso. Observer que foi adicionado um segundo parâmetro aos parâmetros da função chamada dentro de map:

const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map(
  (number,index) =><li key={index}>{number}</li>
);

  ReactDOM.render(
  <ul>{listItems}</ul>,
  document.getElementById('root')
);

Visão geral da estrutura da aplicação

A aplicação é um sistema de cadastro de livros de uma biblioteca e o cliente React consome uma api Rest CRUD implementada por um servidor Spring Boot.

Esses componentes chamam métodos de serviço, definidos no arquivo /services/Endpoints.js, que usam axios para fazer requisições HTTP e receber respostas.

Criando o app usando script padrão

npx create-react-app aula-react-crud

Instalação de dependências

Neste projeto vamos utilizar três dependências:

  1. Bootstrap: um kit de ferramentas para estilizar front-end
  2. React Router: uma ferramenta que permite manipular rotas em um aplicativo da web
  3. Axios: um cliente HTTP

yarn add bootstrap react-router-dom axios

Estrutura de diretórios e arquivos do projeto

Arquivo src/index.js

import React from "react";
import ReactDOM from "react-dom";

import App from "./App";

ReactDOM.render(<App />,  document.getElementById("root")
);

Arquivo src/App.js

import React from "react";
import { BrowserRouter, Routes, Route, Link } from "react-router-dom";
import "bootstrap/dist/css/bootstrap.min.css";
import "./App.css";

import ListagemLivros from "./components/ListagemLivros.js";
import NovoLivro from "./components/NovoLivro.js";
import EditaLivro from "./components/EditaLivro.js";

function App() {
  return (
    <BrowserRouter>
      <nav className="container navbar navbar-expand navbar-dark bg-dark">
        <h1 className="navbar-brand">Exemplo CRUD</h1>
        <div className="navbar-nav mr-auto">
          <li className="nav-item">
            <Link to="/livros" className="nav-link">
              Livros
            </Link>
          </li>
          <li className="nav-item">
            <Link to="/novo" className="nav-link">
              Novo livro
            </Link>
          </li>
        </div>
      </nav>

      <div className="container mt-3">
        <Routes>
          <Route path="/" element={<ListagemLivros />} />
          <Route path="novo" element={<NovoLivro />} />
          <Route path="livros/:id" element={<EditaLivro />} />
          <Route path="livros" element={<ListagemLivros />} />
        </Routes>
      </div>
    </BrowserRouter>
  );
}

export default App;

Arquivo services/Endpoints.js

import axios from "axios";

const httpClient = axios.create({
  baseURL: "http://localhost:8080/api",
  headers: {
    "Content-type": "application/json"
  }
})

export const getAll = () => {
  return httpClient.get("/livro");
};

export const get = id => {
  return httpClient.get(`/livro/${id}`);
};

export const create = data => {
  return httpClient.post("/livro", data);
};

export const update = (id, data) => {
  return httpClient.put(`/livro/${id}`, data);
};

export const remove = id => {
  return httpClient.delete(`/livro/${id}`);
};

Construindo os componentes

Listando todos os livros

Arquivo components/ListagemLivros.js

import React, { useState, useEffect } from "react";
import * as api from "../services/Endpoints"
import { Link } from "react-router-dom";

const ListagemLivros = () => {
    const [livros, setLivros] = useState([]);
    const [livroSelecionado, setLivroSelecionado] = useState(null);
    const [currentIndex, setCurrentIndex] = useState(-1);

    useEffect(() => {
        buscaLivros();
    }, []);

    const buscaLivros = () => {
        api.getAll()
            .then(response => {
                setLivros(response.data);
                console.log(response.data);
            })
            .catch(e => {
                console.log(e);
            });
    };

    const setLivroAtivo = (livro, index) => {
        setLivroSelecionado(livro);
        setCurrentIndex(index);
    };

    return (
        <div className="container list row">
            <div className="col-md-6">
                <h4>Livros</h4>
                <ul className="list-group py-1">
                    {livros &&
                        livros.map((livro, index) => (
                            <li  className={"list-group-item " + (index === currentIndex ? "active" : "")}
                                 onClick={() => setLivroAtivo(livro, index)}
                                 key={index}
                            >{livro.titulo}</li>
                        ))}
                </ul>
            </div>


            <div className="col-md-6">
                {livroSelecionado ? (
                    <div>
                        <h4>Detalhe</h4>
                        <div>
                            <label>
                                <strong>Titulo:</strong>
                            </label>{" "}
                            {livroSelecionado.titulo}
                        </div>
                        <div>
                            <label>
                                <strong>Autor:</strong>
                            </label>{" "}
                            {livroSelecionado.autor}
                        </div>

                        <Link to={"/livros/" + livroSelecionado.id} className="btn btn-warning">Editar</Link>
                    </div>
                ) : (
                    <div>
                        <br />
                        <p>Escolha um livro ...</p>
                    </div>
                )}
            </div>
        </div>
    );
};

export default ListagemLivros;

Criando um livro

Arquivo components/NovoLivro.js

import React, { useState } from "react";
import * as api from "../services/Endpoints"

const NovoLivro = () => {
    const estadoInicialLivro = {
        id: null,
        titulo: "",
        autor: "",
    };
    const [livro, setLivro] = useState(estadoInicialLivro);
    const [submitted, setSubmitted] = useState(false);

    const trataCampo = (event) => {
        const { name, value } = event.target;
        setLivro({ ...livro, [name]: value });
    };

    const novo = () => {
        setLivro(estadoInicialLivro);
        setSubmitted(false);
    };

    const enviarLivro = () => {
        var data = {
            titulo: livro.titulo,
            autor: livro.autor
        };
        console.log(data)
        api.create(data)
            .then(response => {
                setLivro({
                    id: response.data.id,
                    titulo: response.data.titulo,
                    autor: response.data.autor,
                });
                setSubmitted(true);
                console.log(response.data);
            })
            .catch(e => { console.log(e); });
    };

    return (
        <div className="submit-form">
            {submitted ? (
                <div>
                    <h4>Livro cadastrado com sucesso!</h4>
                    <button className="btn btn-success" onClick={novo}>Novo</button>
                </div>
            ) : (
                <div>
                    <div className="form-group">
                        <label htmlFor="titulo">Titulo</label>
                        <input
                            type="text"
                            className="form-control"
                            id="titulo"
                            required
                            value={livro.titulo}
                            onChange={trataCampo}
                            name="titulo"
                        />
                    </div>

                    <div className="form-group mt-4">
                        <label htmlFor="description">Autor</label>
                        <input
                            type="text"
                            className="form-control"
                            id="autor"
                            required
                            value={livro.autor}
                            onChange={trataCampo}
                            name="autor"
                        />
                    </div>

                    <button onClick={enviarLivro} className="btn btn-success mt-4">Cadastrar</button>
                </div>
            )}
        </div>
    );
}

export default NovoLivro;

Editando um livro

Arquivo components/EditaLivro.js

import React, { useState, useEffect } from "react";
import * as api from "../services/Endpoints"

const EditaLivro = props => {
    const estadoInicial = {
        id: null,
        titulo: "",
        autor: "",
    };

    const [livro, setLivro] = useState(estadoInicial);
    const [message, setMessage] = useState("");

    const getLivro = (id) => {
        api.get(id)
            .then(response => {
                setLivro(response.data);
                console.log(response.data);
            })
            .catch(e => {
                console.log(e);
            });
    };

    useEffect(() => {
        getLivro(props.match.params.id);
    }, [props.match.params.id]);

    const trataCampo = event => {
        const { name, value } = event.target;
        setLivro({ ...livro, [name]: value });
    };

    const atualizarLivro = () => {
        api.update(livro.id, livro)
            .then(response => {
                console.log(response.data);
                setMessage("Livro atualizado!");
            })
            .catch(e => { console.log(e); });
    };

    const excluirLivro = () => {
        api.remove(livro.id)
            .then(response => {
                console.log(response.data);
                props.history.push("/livros");
            })
            .catch(e => { console.log(e); });
    };

    return (
        <div>
            {livro ? (
                <div className="edit-form">
                    <h4>Livro</h4>
                    <form>
                        <div className="form-group">
                            <label htmlFor="titulo">Titulo</label>
                            <input
                                type="text"
                                className="form-control"
                                id="titulo"
                                name="titulo"
                                value={livro.titulo}
                                onChange={trataCampo}
                            />
                        </div>
                        <div className="form-group mt-3">
                            <label htmlFor="description">Autor</label>
                            <input
                                type="text"
                                className="form-control"
                                id="autor"
                                name="autor"
                                value={livro.autor}
                                onChange={trataCampo}
                            />
                        </div>
                    </form>

                    <button className="btn btn-warning danger mt-3" onClick={excluirLivro}>Excluir</button>
                    <button type="submit" className="btn btn-success mt-3 mx-3" onClick={atualizarLivro}>
                        Atualizar
                    </button>
                    <p>{message}</p>
                </div>
            ) : (
                <div>
                    <br />
                    <p>Selecione um livro ...</p>
                </div>
            )}
        </div>
    );
};

export default EditaLivro;