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
Em breve irei postar mais algumas coisas interessantes sobre essa poderosa biblioteca React.