Pesquisar

13/08/2022

Implementando rotas no react com react-router-dom

Olá galera.

Gostamos muito das funcionalidades do React e a forma em que renderiza as páginas.

Mas como podemos chamar nossos componentes individualmente ou componentes aninhados?

O objetivo desse passo a passo é mostrar a facilidade do roteamento com o uso do react-router-dom.

Os códigos desse artigo foram criados com base na documentação do react-router-dom link abaixo.

https://reactrouter.com/docs/en/v6/getting-started/tutorial

Fiz algumas alterações como separar o css do javascript.

Criando o projeto React inicial:

npx create-react-app 1react-router

Explicando:

Usei 1react-router porque facilita o acesso a pasta do projeto. Se você seguir esse modelo para entrar na pasta basta digitar.

cd 1r+TAB e aí não precisa escrever o restante do nome da pasta beleza.

Depois de criar o projeto e entrar na pasta. Digite:

npm install react-router-dom.

npm start

Verifique se tá tudo beleza e seu package.json está como abaixo:

{

  "name": "1react-router",

  "version": "0.1.0",

  "private": true,

  "dependencies": {

    "react": "^18.2.0",

    "react-dom": "^18.2.0",

    "react-router-dom": "^6.3.0",

    "react-scripts": "0.9.5"

  },

  "scripts": {

    "start": "react-scripts start",

    "build": "react-scripts build",

    "test": "react-scripts test --env=jsdom",

    "eject": "react-scripts eject"

  }

}

Se não estiver copie esse acima cole no seu e rode: npm install.

Depois de deixar tudo como acima...

Vamos alterar o arquivo App.js na pasta src.

O arquivo original tem várias coisas que não vamos precisar, por isso apague tudo e vamos criar um do zero, como abaixo:

export default function App() {

  return (

    <div>

      <h1>Bookkeeper!</h1>

    </div>

  );

}

Modifique também o arquivo src/index.js

Pode deixar como abaixo:

import ReactDOM from "react-dom/client";

import App from "./App";

const root = ReactDOM.createRoot(

  document.getElementById("root")

);

root.render(<App />);

Agora em src/index.js (ou main.js) vamos importar BorwserRouter e envolver o componente App dentro dele. Veja abaixo:

import ReactDOM from "react-dom/client";

import { BrowserRouter } from "react-router-dom";

import App from "./App";


const root = ReactDOM.createRoot(

  document.getElementById("root")

);

root.render(

  <BrowserRouter>

    <App />

  </BrowserRouter>

);


Vamos colocar dois links dentro de src/App.js

import { Link } from "react-router-dom";

import './App.css';

export default function App() {

  return (

    <div>

      <h1>Bookkeeper</h1>

      <nav>

        <Link to="/invoices">Invoices</Link> |{" "}

        <Link to="/expenses">Expenses</Link>

      </nav>

    </div>

  );

}


Visto que já fizemos o importe acima remova o conteudo de App.css e coloque o seguinte:

nav{

border-bottom: solid 1px;

padding-bottom: 1rem;

}

main{

padding: 1rem;

}


Agora crie os dois componentes na pasta como abaixo (crie a pasta routes se ainda não criou):

src/routes/invoices.jsx

src/routes/expenses.jsx

Para facilitar as coisas depois crie também os arquivos css:

src/routes/invoices.css

src/routes/expenses.css


Vai ficar mais fácil fazer a manutenção depois no css bem como acrescentar mais detalhes do front.


Agora que defininimos os componentes Invoices e Expences que serão chamados no roteamento, vamos criá-los na pasta src/routes.

export default function Expenses() {

  return (

    <main style={{ padding: "1rem 0" }}>

      <h2>Expenses</h2>

    </main>

  );

}


export default function Invoices() {

  return (

    <main style={{ padding: "1rem 0" }}>

      <h2>Invoices</h2>

    </main>

  );

}


Conteúdo css equivalentes:

main{

padding: 1rem 0;

}


Agora vamos configurar as rotas em index.js ou main.js:

import ReactDOM from "react-dom/client";

import {

  BrowserRouter,

  Routes,

  Route,

} from "react-router-dom";

import App from "./App";

import Expenses from "./routes/expenses";

import Invoices from "./routes/invoices";


const root = ReactDOM.createRoot(

  document.getElementById("root")

);

root.render(

  <BrowserRouter>

    <Routes>

      <Route path="/" element={<App />} />

      <Route path="expenses" element={<Expenses />} />

      <Route path="invoices" element={<Invoices />} />

    </Routes>

  </BrowserRouter>

);


Observe que a home central ("/") vai ser renderizado App e em "/expenses" será renderizado o componente Expenses.


Se você testar agora seus links verá que seu layout não se tornou persistente.


Os elementos App Expenses e Invoices são irmãos. Vamos tornar App pai dos demais, veja abaixo a alteração em index.js (ou main.js)


import ReactDOM from "react-dom/client";

import {

  BrowserRouter,

  Routes,

  Route,

} from "react-router-dom";

import App from "./App";

import Expenses from "./routes/expenses";

import Invoices from "./routes/invoices";


const root = ReactDOM.createRoot(

  document.getElementById("root")

);

root.render(

  <BrowserRouter>

    <Routes>

      <Route path="/" element={<App />}>

        <Route path="expenses" element={<Expenses />} />

        <Route path="invoices" element={<Invoices />} />

      </Route>

    </Routes>

  </BrowserRouter>

);


Observe que App envolveu os demais elementos.


Agora para que a persistencia do layout funcone precisamos chamar Outlet em App.js na rota pai.


import { Outlet, Link } from "react-router-dom";

import './App.css';

export default function App() {

  return (

    <div>

      <h1>Bookkeeper</h1>

      <nav>

        <Link to="/invoices">Invoices</Link> |{" "}

        <Link to="/expenses">Expenses</Link>

      </nav>

      <Outlet />

    </div>

  );

}


Agora clique novamente no link e veja que a rota pai tornou-se presistente enquanto ocorre a troca dos elementos filhos.


Agora imagine uma aplicação que retorna dados de servidores ou banco de dados. É possível linkar esses dados individualmente rotear.

Vamos criar uma api fake aqui crie o arquivo data.js na pasta src com o conteúdo abaixo.

let invoices = [

  {

    name: "Santa Monica",

    number: 1995,

    amount: "$10,800",

    due: "12/05/1995",

  },

  {

    name: "Stankonia",

    number: 2000,

    amount: "$8,000",

    due: "10/31/2000",

  },

  {

    name: "Ocean Avenue",

    number: 2003,

    amount: "$9,500",

    due: "07/22/2003",

  },

  {

    name: "Tubthumper",

    number: 1997,

    amount: "$14,000",

    due: "09/01/1997",

  },

  {

    name: "Wide Open Spaces",

    number: 1998,

    amount: "$4,600",

    due: "01/27/1998",

  },

];


export function getInvoices() {

  return invoices;

}


Faça o importe em invoices.jsx:

import { Link } from "react-router-dom";

import { getInvoices } from "../data";


export default function Invoices() {

  let invoices = getInvoices();

  return (

    <div>

      <nav>

        {invoices.map((invoice) => (

          <Link

            to={`/invoices/${invoice.number}`}

            key={invoice.number}

          >

            {invoice.name}

          </Link>

        ))}

      </nav>

    </div>

  );

}

Atualize o seu css equivalente invoices.css:


div{

display: flex;

}

main{

padding: 1rem 0;

}

nav{

border-right: solid 1px;

padding: 1rem;

}

.links{

display: block; 

margin: 1rem 0; 

}


Se você clicar em um link de fatura nesse ponto não retorna nada. Vamos corrigir isso e avisar o leitor de algum erro:

Chame um elemento que retornará em caso de uma requisição de rota indefinida. Altere isso em index.js:

    <Route

      path="*"

      element={

        <main>

          <p>There's nothing here!</p>

        </main>

      }

    />

altere seu index.css para: 

body {

  margin: 0;

  padding: 0;

  font-family: sans-serif;

}

main{

padding: 1rem;


    

Agora vamos rotear um dado retornado do banco de dados. Em nosso caso aquela api fake.

Para isso crie mais um componente src/routes/invoice.jsx com o seguinte conteúdo:

export default function Invoice() {

  return <h2>Invoice #???</h2>;

}


Insira esse componente como filho de Invoices.

<Routes>

  <Route path="/" element={<App />}>

    <Route path="expenses" element={<Expenses />} />

    <Route path="invoices" element={<Invoices />}>

      <Route path=":invoiceId" element={<Invoice />} />

    </Route>

    <Route

      path="*"

      element={

        <main style={{ padding: "1rem" }}>

          <p>There's nothing here!</p>

        </main>

      }

    />

  </Route>

</Routes>


Agora criamos uma url que corresponde ao item retornado.

Adicionamos também uma segunda camada de aninhamento que fica como abaixo:

App pai de invoices e invoice filho de invoices.


Se você clicar em uma fatura ela ainda não aparece.

Então vamos chamar Outlet novamente agora na rota filha de Invoices.


import React from 'react';

import './invoices.css';

import { Outlet, Link } from "react-router-dom";

import { getInvoices } from "../data";


export default function Invoices() {

let invoices = getInvoices();

return (

<div style={{ display: "flex" }}>

<nav>

{invoices.map((invoice) => (

<Link className="links"

to={`/invoices/${invoice.number}`}

key={invoice.number}>

{invoice.name}

</Link>

))}

</nav>

<Outlet />

</div>

);

}


Atualize seu invoices.css

div{

display: flex;

}

main{

padding: 1rem 0;

}

nav{

border-right: solid 1px;

padding: 1rem;

}

.links{

display: block; 

margin: 1rem 0;

}

Atualize seu invoice.jsx como abaixo para pegar o parametro retornado pela url:

import { useParams } from "react-router-dom";

export default function Invoice() {

  let params = useParams();

  return <h2>Invoice: {params.invoiceId}</h2>;

}

Agora em data.js adicione uma nova função para pesuisar faturas pelo número:

export function getInvoice(number) {

  return invoices.find(

    (invoice) => invoice.number === number

  );

}

Agora voltando ao componente do arquivo invoice.jsx usamos o parametro para procurar uma fatura e exibir mais informações:

import React from 'react';

import { useParams} from 'react-router-dom';

import './invoice.css';

import { getInvoice} from '../data';

export default function Invoice(){

let params = useParams();

let invoice = getInvoice(parseInt(params.invoiceId, 10));

return (

<main style={{  }}>

<h2>Total Due: {invoice.amount}</h2>

<p>

{invoice.name}: {invoice.number}

</p>

<p>Due Date: {invoice.due}</p>

</main>

);

}


Fechando...

O que foi desenvolvido aqui com a ajuda da documentação pode ser conferido nesse vídeo do youtube.

https://youtu.be/luyfv7r1fe4

Os arquivos estão nesse repositório no github.

https://github.com/aondenet-sinval/react-router-basic.git

Com certeza há muito mais coisas a aprender sobre rect-router-dom essa biblioteca é fantastica.

Em breve irei postar mais algumas coisas interessantes sobre essa poderosa biblioteca React.

Novos modelos sites Pousada Lanchonete

Postagens mais visitadas