ReactJS
Projeto Next.js
$ npx create-next-app
✔ What is your project named? invest-app
✔ Would you like to use TypeScript with this project? No / Yes
✔ Would you like to use ESLint with this project? No / Yes
✔ Would you like to use Tailwind CSS with this project? No / Yes
✔ Would you like to use `src/` directory with this project? No / Yes
✔ Use App Router (recommended)? No / Yes
✔ Would you like to customize the default import alias? No / Yes
Creating a new Next.js app in /codes/react/introduction/invest-app.
Using npm.
Initializing project with template: app-tw
Installing dependencies:
- react
- react-dom
- next
- tailwindcss
- postcss
- autoprefixer
- eslint
- eslint-config-next
added 323 packages, and audited 324 packages in 28s
117 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
$ npx create-next-app
✔ What is your project named? invest-app
✔ Would you like to use TypeScript with this project? No / Yes
✔ Would you like to use ESLint with this project? No / Yes
✔ Would you like to use Tailwind CSS with this project? No / Yes
✔ Would you like to use `src/` directory with this project? No / Yes
✔ Use App Router (recommended)? No / Yes
✔ Would you like to customize the default import alias? No / Yes
Creating a new Next.js app in /codes/react/introduction/invest-app.
Using npm.
Initializing project with template: app-tw
Installing dependencies:
- react
- react-dom
- next
- tailwindcss
- postcss
- autoprefixer
- eslint
- eslint-config-next
added 323 packages, and audited 324 packages in 28s
117 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
Arquivos
invest-app
├── README.md
├── jsconfig.json
├── next.config.js
├── package-lock.json
├── package.json
├── postcss.config.js
├── public
│ ├── next.svg
│ └── vercel.svg
├── src
│ └── app
│ ├── favicon.ico
│ ├── globals.css
│ ├── layout.js
│ └── page.js
└── tailwind.config.js
Arquivos
invest-app
├── README.md
├── jsconfig.json
├── next.config.js
├── package-lock.json
├── package.json
├── postcss.config.js
├── public
│ ├── next.svg
│ └── vercel.svg
├── src
│ └── app
│ ├── favicon.ico
│ ├── globals.css
│ ├── layout.js
│ └── page.js
└── tailwind.config.js
Componentes
Multiplataforma
- Web: react-dom (ReactJS), react-native-dom (React Native)
- Mobile: android-native, ios-native (React Native)
- Desktop: react-native-windows, proton-native (React Native)
- TV: react-native-tvos (React Native)
- Outras
Declaração
Function Component
export default function Home() {
return <h1>Investimentos</h1>
}
export default function Home() {
return <h1>Investimentos</h1>
}
Class Component
export default class App extends React.Component {
render() {
return <h1>Investimentos</h1>;
}
}
export default class App extends React.Component {
render() {
return <h1>Investimentos</h1>;
}
}
Fragment
/codes/react/introduction/invest-app/src/app/page.jsx
export default function Home() {
return (
<>
<h1 className="text-center text-2xl my-12 font-bold">Investimentos</h1>
<div className="investments grid grid-cols-3 gap-3">
</div>
</>
);
}
/codes/react/introduction/invest-app/src/app/page.jsx
export default function Home() {
return (
<>
<h1 className="text-center text-2xl my-12 font-bold">Investimentos</h1>
<div className="investments grid grid-cols-3 gap-3">
</div>
</>
);
}
JavaScript XML (JSX)
Regras
- Return a single root element
- Close all the tags
- camelCase all most of the things!
Curly Braces
- Passing strings with quotes
- Text and Attributes
- double curlies
Exemplo
/codes/react/introduction/invest-app/src/app/page.jsx
import { investments } from '@/data/seed';
import { formatCurrency, formatDate } from '@/lib/format';
export default function Home() {
const investment = {
id: 'b9f2414d-b8dd-484d-8179-83383d10a3fd',
name: 'Tesouro Selic 2029',
value: 10050,
origin: 'Tesouro Nacional',
category: 'Pós',
created_at: '2023-08-22T00:00:00-03:00',
interest: '100% Selic',
};
return (
<>
<h1 className="text-center text-2xl my-12 font-bold">Investimentos</h1>
<div className="investments grid grid-cols-3 gap-3">
<div className="bg-white shadow-md rounded-lg p-4 relative">
<div className="flex justify-between items-center">
<h3 className="investment-name text-lg font-semibold text-gray-700">
{investment.name}
</h3>
<p className="investment-value text-lg font-semibold text-gray-700">
{formatCurrency(investment.value / 100)}
</p>
</div>
<div className="mt-4">
<p className="text-sm text-gray-500">
<span className="font-bold mr-1">Origem:</span>
<span className="investment-origin">{investment.origin}</span>
</p>
<p className="text-sm text-gray-500">
<span className="font-bold mr-1">Categoria:</span>
<span className="investment-category">{investment.category}</span>
</p>
<p className="text-sm text-gray-500">
<span className="font-bold mr-1">Taxa:</span>
<span className="investment-interest">{investment.interest}</span>
</p>
<p className="text-sm text-gray-500">
<span className="font-bold mr-1">Data:</span>
<span className="investment-created_at">
{formatDate(investment.created_at)}
</span>
</p>
</div>
</div>
</div>
</>
);
}
/codes/react/introduction/invest-app/src/app/page.jsx
import { investments } from '@/data/seed';
import { formatCurrency, formatDate } from '@/lib/format';
export default function Home() {
const investment = {
id: 'b9f2414d-b8dd-484d-8179-83383d10a3fd',
name: 'Tesouro Selic 2029',
value: 10050,
origin: 'Tesouro Nacional',
category: 'Pós',
created_at: '2023-08-22T00:00:00-03:00',
interest: '100% Selic',
};
return (
<>
<h1 className="text-center text-2xl my-12 font-bold">Investimentos</h1>
<div className="investments grid grid-cols-3 gap-3">
<div className="bg-white shadow-md rounded-lg p-4 relative">
<div className="flex justify-between items-center">
<h3 className="investment-name text-lg font-semibold text-gray-700">
{investment.name}
</h3>
<p className="investment-value text-lg font-semibold text-gray-700">
{formatCurrency(investment.value / 100)}
</p>
</div>
<div className="mt-4">
<p className="text-sm text-gray-500">
<span className="font-bold mr-1">Origem:</span>
<span className="investment-origin">{investment.origin}</span>
</p>
<p className="text-sm text-gray-500">
<span className="font-bold mr-1">Categoria:</span>
<span className="investment-category">{investment.category}</span>
</p>
<p className="text-sm text-gray-500">
<span className="font-bold mr-1">Taxa:</span>
<span className="investment-interest">{investment.interest}</span>
</p>
<p className="text-sm text-gray-500">
<span className="font-bold mr-1">Data:</span>
<span className="investment-created_at">
{formatDate(investment.created_at)}
</span>
</p>
</div>
</div>
</div>
</>
);
}
Propriedades
props
/codes/react/introduction/invest-app/src/app/page.jsx
import InvestmentCard from '@/components/InvestmentCard';
export default function Home() {
const investment = {
id: 'b9f2414d-b8dd-484d-8179-83383d10a3fd',
name: 'Tesouro Selic 2029',
value: 10050,
origin: 'Tesouro Nacional',
category: 'Pós',
created_at: '2023-08-22T00:00:00-03:00',
interest: '100% Selic',
};
return (
<>
<h1 className="text-center text-2xl my-12 font-bold">Investimentos</h1>
<div className="investments grid grid-cols-3 gap-3">
<InvestmentCard investment={investment} />
</div>
</>
);
}
/codes/react/introduction/invest-app/src/app/page.jsx
import InvestmentCard from '@/components/InvestmentCard';
export default function Home() {
const investment = {
id: 'b9f2414d-b8dd-484d-8179-83383d10a3fd',
name: 'Tesouro Selic 2029',
value: 10050,
origin: 'Tesouro Nacional',
category: 'Pós',
created_at: '2023-08-22T00:00:00-03:00',
interest: '100% Selic',
};
return (
<>
<h1 className="text-center text-2xl my-12 font-bold">Investimentos</h1>
<div className="investments grid grid-cols-3 gap-3">
<InvestmentCard investment={investment} />
</div>
</>
);
}
/codes/react/introduction/invest-app/src/components/InvestmentCard.jsx
import { formatCurrency, formatDate } from '@/lib/format';
export default function InvestmentCard(props) {
return (
<div className="bg-white shadow-md rounded-lg p-4 relative">
<div className="flex justify-between items-center">
<h3 className="investment-name text-lg font-semibold text-gray-700">
{props.investment.name}
</h3>
<p className="investment-value text-lg font-semibold text-gray-700">
{formatCurrency(props.investment.value / 100)}
</p>
</div>
<div className="mt-4">
<p className="text-sm text-gray-500">
<span className="font-bold mr-1">Origem:</span>
<span className="investment-origin">{props.investment.origin}</span>
</p>
<p className="text-sm text-gray-500">
<span className="font-bold mr-1">Categoria:</span>
<span className="investment-category">{props.investment.category}</span>
</p>
<p className="text-sm text-gray-500">
<span className="font-bold mr-1">Taxa:</span>
<span className="investment-interest">{props.investment.interest}</span>
</p>
<p className="text-sm text-gray-500">
<span className="font-bold mr-1">Data:</span>
<span className="investment-created_at">
{formatDate(props.investment.created_at)}
</span>
</p>
</div>
</div>
);
}
/codes/react/introduction/invest-app/src/components/InvestmentCard.jsx
import { formatCurrency, formatDate } from '@/lib/format';
export default function InvestmentCard(props) {
return (
<div className="bg-white shadow-md rounded-lg p-4 relative">
<div className="flex justify-between items-center">
<h3 className="investment-name text-lg font-semibold text-gray-700">
{props.investment.name}
</h3>
<p className="investment-value text-lg font-semibold text-gray-700">
{formatCurrency(props.investment.value / 100)}
</p>
</div>
<div className="mt-4">
<p className="text-sm text-gray-500">
<span className="font-bold mr-1">Origem:</span>
<span className="investment-origin">{props.investment.origin}</span>
</p>
<p className="text-sm text-gray-500">
<span className="font-bold mr-1">Categoria:</span>
<span className="investment-category">{props.investment.category}</span>
</p>
<p className="text-sm text-gray-500">
<span className="font-bold mr-1">Taxa:</span>
<span className="investment-interest">{props.investment.interest}</span>
</p>
<p className="text-sm text-gray-500">
<span className="font-bold mr-1">Data:</span>
<span className="investment-created_at">
{formatDate(props.investment.created_at)}
</span>
</p>
</div>
</div>
);
}
Object (double curlies)
/codes/react/introduction/invest-app/src/app/page.jsx
<InvestmentCard
id="b9f2414d-b8dd-484d-8179-83383d10a3fd"
name={`Tesouro Selic ${2029}`}
value={10050}
origin="Tesouro Nacional"
category="Pós"
created_at="2023-08-22T00:00:00-03:00"
interest="100% Selic"
/>
/codes/react/introduction/invest-app/src/app/page.jsx
<InvestmentCard
id="b9f2414d-b8dd-484d-8179-83383d10a3fd"
name={`Tesouro Selic ${2029}`}
value={10050}
origin="Tesouro Nacional"
category="Pós"
created_at="2023-08-22T00:00:00-03:00"
interest="100% Selic"
/>
/codes/react/introduction/invest-app/src/app/page.jsx
<InvestmentCard {{
id: 'b9f2414d-b8dd-484d-8179-83383d10a3fd',
name: 'Tesouro Selic 2029',
value: 10050,
origin: 'Tesouro Nacional',
category: 'Pós',
created_at: '2023-08-22T00:00:00-03:00',
interest: '100% Selic',
}} />
/codes/react/introduction/invest-app/src/app/page.jsx
<InvestmentCard {{
id: 'b9f2414d-b8dd-484d-8179-83383d10a3fd',
name: 'Tesouro Selic 2029',
value: 10050,
origin: 'Tesouro Nacional',
category: 'Pós',
created_at: '2023-08-22T00:00:00-03:00',
interest: '100% Selic',
}} />
/codes/react/introduction/invest-app/src/components/InvestmentCard.jsx
import { formatCurrency, formatDate } from '@/lib/format';
export default function InvestmentCard({
name,
value,
origin,
category,
interest,
created_at,
}) {
return (
<div className="bg-white shadow-md rounded-lg p-4 relative">
<div className="flex justify-between items-center">
<h3 className="investment-name text-lg font-semibold text-gray-700">
{name}
</h3>
<p className="investment-value text-lg font-semibold text-gray-700">
{formatCurrency(value / 100)}
</p>
</div>
<div className="mt-4">
<p className="text-sm text-gray-500">
<span className="font-bold mr-1">Origem:</span>
<span className="investment-origin">{origin}</span>
</p>
<p className="text-sm text-gray-500">
<span className="font-bold mr-1">Categoria:</span>
<span className="investment-category">{category}</span>
</p>
<p className="text-sm text-gray-500">
<span className="font-bold mr-1">Taxa:</span>
<span className="investment-interest">{interest}</span>
</p>
<p className="text-sm text-gray-500">
<span className="font-bold mr-1">Data:</span>
<span className="investment-created_at">{formatDate(created_at)}</span>
</p>
</div>
</div>
);
}
/codes/react/introduction/invest-app/src/components/InvestmentCard.jsx
import { formatCurrency, formatDate } from '@/lib/format';
export default function InvestmentCard({
name,
value,
origin,
category,
interest,
created_at,
}) {
return (
<div className="bg-white shadow-md rounded-lg p-4 relative">
<div className="flex justify-between items-center">
<h3 className="investment-name text-lg font-semibold text-gray-700">
{name}
</h3>
<p className="investment-value text-lg font-semibold text-gray-700">
{formatCurrency(value / 100)}
</p>
</div>
<div className="mt-4">
<p className="text-sm text-gray-500">
<span className="font-bold mr-1">Origem:</span>
<span className="investment-origin">{origin}</span>
</p>
<p className="text-sm text-gray-500">
<span className="font-bold mr-1">Categoria:</span>
<span className="investment-category">{category}</span>
</p>
<p className="text-sm text-gray-500">
<span className="font-bold mr-1">Taxa:</span>
<span className="investment-interest">{interest}</span>
</p>
<p className="text-sm text-gray-500">
<span className="font-bold mr-1">Data:</span>
<span className="investment-created_at">{formatDate(created_at)}</span>
</p>
</div>
</div>
);
}
JSX spread syntax
/codes/react/introduction/invest-app/src/app/page.jsx
const investment = {
id: 'b9f2414d-b8dd-484d-8179-83383d10a3fd',
name: 'Tesouro Selic 2029',
value: 10050,
origin: 'Tesouro Nacional',
category: 'Pós',
created_at: '2023-08-22T00:00:00-03:00',
interest: '100% Selic',
};
<InvestmentCard {...investment} />
/codes/react/introduction/invest-app/src/app/page.jsx
const investment = {
id: 'b9f2414d-b8dd-484d-8179-83383d10a3fd',
name: 'Tesouro Selic 2029',
value: 10050,
origin: 'Tesouro Nacional',
category: 'Pós',
created_at: '2023-08-22T00:00:00-03:00',
interest: '100% Selic',
};
<InvestmentCard {...investment} />
/codes/react/introduction/invest-app/src/components/InvestmentCard.jsx
import { formatCurrency, formatDate } from '@/lib/format';
export default function InvestmentCard({
name,
value,
origin,
category,
interest,
created_at,
}) {
return (
<div className="bg-white shadow-md rounded-lg p-4 relative">
<div className="flex justify-between items-center">
<h3 className="investment-name text-lg font-semibold text-gray-700">
{name}
</h3>
<p className="investment-value text-lg font-semibold text-gray-700">
{formatCurrency(value / 100)}
</p>
</div>
<div className="mt-4">
<p className="text-sm text-gray-500">
<span className="font-bold mr-1">Origem:</span>
<span className="investment-origin">{origin}</span>
</p>
<p className="text-sm text-gray-500">
<span className="font-bold mr-1">Categoria:</span>
<span className="investment-category">{category}</span>
</p>
<p className="text-sm text-gray-500">
<span className="font-bold mr-1">Taxa:</span>
<span className="investment-interest">{interest}</span>
</p>
<p className="text-sm text-gray-500">
<span className="font-bold mr-1">Data:</span>
<span className="investment-created_at">{formatDate(created_at)}</span>
</p>
</div>
</div>
);
}
/codes/react/introduction/invest-app/src/components/InvestmentCard.jsx
import { formatCurrency, formatDate } from '@/lib/format';
export default function InvestmentCard({
name,
value,
origin,
category,
interest,
created_at,
}) {
return (
<div className="bg-white shadow-md rounded-lg p-4 relative">
<div className="flex justify-between items-center">
<h3 className="investment-name text-lg font-semibold text-gray-700">
{name}
</h3>
<p className="investment-value text-lg font-semibold text-gray-700">
{formatCurrency(value / 100)}
</p>
</div>
<div className="mt-4">
<p className="text-sm text-gray-500">
<span className="font-bold mr-1">Origem:</span>
<span className="investment-origin">{origin}</span>
</p>
<p className="text-sm text-gray-500">
<span className="font-bold mr-1">Categoria:</span>
<span className="investment-category">{category}</span>
</p>
<p className="text-sm text-gray-500">
<span className="font-bold mr-1">Taxa:</span>
<span className="investment-interest">{interest}</span>
</p>
<p className="text-sm text-gray-500">
<span className="font-bold mr-1">Data:</span>
<span className="investment-created_at">{formatDate(created_at)}</span>
</p>
</div>
</div>
);
}
JSX as children
/codes/react/introduction/invest-app/src/app/page.jsx
const investment = {
id: 'b9f2414d-b8dd-484d-8179-83383d10a3fd',
name: 'Tesouro Selic 2029',
value: 10050,
origin: 'Tesouro Nacional',
category: 'Pós',
created_at: '2023-08-22T00:00:00-03:00',
interest: '100% Selic',
};
<InvestmentCard {...investment}>
<strong>#</strong>
{investment.name}
</InvestmentCard>
/codes/react/introduction/invest-app/src/app/page.jsx
const investment = {
id: 'b9f2414d-b8dd-484d-8179-83383d10a3fd',
name: 'Tesouro Selic 2029',
value: 10050,
origin: 'Tesouro Nacional',
category: 'Pós',
created_at: '2023-08-22T00:00:00-03:00',
interest: '100% Selic',
};
<InvestmentCard {...investment}>
<strong>#</strong>
{investment.name}
</InvestmentCard>
/codes/react/introduction/invest-app/src/components/InvestmentCard.jsx
import { formatCurrency, formatDate } from '@/lib/format';
export default function InvestmentCard({
name,
value,
origin,
category,
interest,
created_at,
children
}) {
return (
<div className="bg-white shadow-md rounded-lg p-4 relative">
<div className="flex justify-between items-center">
<h3 className="investment-name text-lg font-semibold text-gray-700">
{children}
</h3>
<p className="investment-value text-lg font-semibold text-gray-700">
{formatCurrency(value / 100)}
</p>
</div>
<div className="mt-4">
<p className="text-sm text-gray-500">
<span className="font-bold mr-1">Origem:</span>
<span className="investment-origin">{origin}</span>
</p>
<p className="text-sm text-gray-500">
<span className="font-bold mr-1">Categoria:</span>
<span className="investment-category">{category}</span>
</p>
<p className="text-sm text-gray-500">
<span className="font-bold mr-1">Taxa:</span>
<span className="investment-interest">{interest}</span>
</p>
<p className="text-sm text-gray-500">
<span className="font-bold mr-1">Data:</span>
<span className="investment-created_at">{formatDate(created_at)}</span>
</p>
</div>
</div>
);
}
/codes/react/introduction/invest-app/src/components/InvestmentCard.jsx
import { formatCurrency, formatDate } from '@/lib/format';
export default function InvestmentCard({
name,
value,
origin,
category,
interest,
created_at,
children
}) {
return (
<div className="bg-white shadow-md rounded-lg p-4 relative">
<div className="flex justify-between items-center">
<h3 className="investment-name text-lg font-semibold text-gray-700">
{children}
</h3>
<p className="investment-value text-lg font-semibold text-gray-700">
{formatCurrency(value / 100)}
</p>
</div>
<div className="mt-4">
<p className="text-sm text-gray-500">
<span className="font-bold mr-1">Origem:</span>
<span className="investment-origin">{origin}</span>
</p>
<p className="text-sm text-gray-500">
<span className="font-bold mr-1">Categoria:</span>
<span className="investment-category">{category}</span>
</p>
<p className="text-sm text-gray-500">
<span className="font-bold mr-1">Taxa:</span>
<span className="investment-interest">{interest}</span>
</p>
<p className="text-sm text-gray-500">
<span className="font-bold mr-1">Data:</span>
<span className="investment-created_at">{formatDate(created_at)}</span>
</p>
</div>
</div>
);
}
Lista e Chaves
/codes/react/introduction/invest-app/src/data/seed.js
export const investments = [
{
id: 'b9f2414d-b8dd-484d-8179-83383d10a3fd',
name: 'Tesouro Selic 2029',
value: 10050,
origin: 'Tesouro Nacional',
category: 'Pós',
created_at: '2023-08-22T00:00:00-03:00',
interest: '100% Selic',
},
{
id: 'bb0a4c9b-8eea-4d79-a248-39c8b846fa9e',
name: 'Tesouro IPCA 2029',
value: 10000,
origin: 'Tesouro Nacional',
category: 'IPCA',
created_at: '2023-08-22T00:00:00-03:00',
interest: 'IPCA + 5,83%',
},
];
/codes/react/introduction/invest-app/src/data/seed.js
export const investments = [
{
id: 'b9f2414d-b8dd-484d-8179-83383d10a3fd',
name: 'Tesouro Selic 2029',
value: 10050,
origin: 'Tesouro Nacional',
category: 'Pós',
created_at: '2023-08-22T00:00:00-03:00',
interest: '100% Selic',
},
{
id: 'bb0a4c9b-8eea-4d79-a248-39c8b846fa9e',
name: 'Tesouro IPCA 2029',
value: 10000,
origin: 'Tesouro Nacional',
category: 'IPCA',
created_at: '2023-08-22T00:00:00-03:00',
interest: 'IPCA + 5,83%',
},
];
/codes/react/introduction/invest-app/src/app/page.jsx
import InvestmentCard from '@/components/InvestmentCard';
import { investments } from '@/data/seed';
export default function Home() {
return (
<>
<h1 className="text-center text-2xl my-12 font-bold">Investimentos</h1>
<div className="investments grid grid-cols-3 gap-3">
{investments.map((investment) => (
<InvestmentCard investment={investment} key={investment.id} />
))}
</div>
</>
);
}
/codes/react/introduction/invest-app/src/app/page.jsx
import InvestmentCard from '@/components/InvestmentCard';
import { investments } from '@/data/seed';
export default function Home() {
return (
<>
<h1 className="text-center text-2xl my-12 font-bold">Investimentos</h1>
<div className="investments grid grid-cols-3 gap-3">
{investments.map((investment) => (
<InvestmentCard investment={investment} key={investment.id} />
))}
</div>
</>
);
}
Next.js
Fetching Data (Cache)
/codes/react/introduction/invest-app/src/app/page.jsx
import InvestmentCard from '@/components/InvestmentCard';
import Storage from '@/services/supabase';
async function getData() {
return Storage.read('investments');
}
export default async function Home() {
const investments = await getData();
return (
<>
<h1 className="text-center text-2xl my-12 font-bold">Investimentos</h1>
<div className="investments grid grid-cols-3 gap-3">
{investments.map((investment) => (
<InvestmentCard investment={investment} key={investment.id} />
))}
</div>
</>
);
}
/codes/react/introduction/invest-app/src/app/page.jsx
import InvestmentCard from '@/components/InvestmentCard';
import Storage from '@/services/supabase';
async function getData() {
return Storage.read('investments');
}
export default async function Home() {
const investments = await getData();
return (
<>
<h1 className="text-center text-2xl my-12 font-bold">Investimentos</h1>
<div className="investments grid grid-cols-3 gap-3">
{investments.map((investment) => (
<InvestmentCard investment={investment} key={investment.id} />
))}
</div>
</>
);
}
Routes
Fonte: Next.js Docs - Routing Fundamentals - Route Segments
Fonte: Next.js Docs - Routing Fundamentals - Defining Routes
Dynamic Routes
/codes/react/introduction/invest-app/src/app/[investment]/page.jsx
import { formatCurrency, formatDate } from '@/lib/format';
import Storage from '@/services/supabase';
export async function generateStaticParams() {
const investments = await Storage.read('investments');
return investments.map((investment) => ({
slug: investment.id,
}));
}
async function getData(slug) {
const investment = await Storage.read('investments', slug);
return investment;
}
export default async function Investment({ params: { slug } }) {
const [{ name, value, origin, category, interest, created_at }] =
await getData(slug);
return (
<>
<h1 className="text-center text-2xl my-12 font-bold">{name}</h1>
<div className="w-64 m-auto">
<p className="text-gray-600 flex justify-between p-1">
<span className="font-bold mr-1">Valor:</span>
<span className="investment-origin">{formatCurrency(value)}</span>
</p>
<p className="text-gray-600 flex justify-between p-1">
<span className="font-bold mr-1">Origem:</span>
<span className="investment-origin">{origin}</span>
</p>
<p className="text-gray-600 flex justify-between p-1">
<span className="font-bold mr-1">Categoria:</span>
<span className="investment-category">{category}</span>
</p>
<p className="text-gray-600 flex justify-between p-1">
<span className="font-bold mr-1">Taxa:</span>
<span className="investment-interest">{interest}</span>
</p>
<p className="text-gray-600 flex justify-between p-1">
<span className="font-bold mr-1">Data:</span>
<span className="investment-created_at">
{formatDate(created_at)}
</span>
</p>
</div>
</>
);
}
/codes/react/introduction/invest-app/src/app/[investment]/page.jsx
import { formatCurrency, formatDate } from '@/lib/format';
import Storage from '@/services/supabase';
export async function generateStaticParams() {
const investments = await Storage.read('investments');
return investments.map((investment) => ({
slug: investment.id,
}));
}
async function getData(slug) {
const investment = await Storage.read('investments', slug);
return investment;
}
export default async function Investment({ params: { slug } }) {
const [{ name, value, origin, category, interest, created_at }] =
await getData(slug);
return (
<>
<h1 className="text-center text-2xl my-12 font-bold">{name}</h1>
<div className="w-64 m-auto">
<p className="text-gray-600 flex justify-between p-1">
<span className="font-bold mr-1">Valor:</span>
<span className="investment-origin">{formatCurrency(value)}</span>
</p>
<p className="text-gray-600 flex justify-between p-1">
<span className="font-bold mr-1">Origem:</span>
<span className="investment-origin">{origin}</span>
</p>
<p className="text-gray-600 flex justify-between p-1">
<span className="font-bold mr-1">Categoria:</span>
<span className="investment-category">{category}</span>
</p>
<p className="text-gray-600 flex justify-between p-1">
<span className="font-bold mr-1">Taxa:</span>
<span className="investment-interest">{interest}</span>
</p>
<p className="text-gray-600 flex justify-between p-1">
<span className="font-bold mr-1">Data:</span>
<span className="investment-created_at">
{formatDate(created_at)}
</span>
</p>
</div>
</>
);
}
Linking and Navigating
/codes/react/introduction/invest-app/src/components/InvestmentCard.jsx
import Link from 'next/link';
import { IconTrash } from '@tabler/icons-react';
import { formatCurrency, formatDate } from '@/lib/format';
export default function InvestmentCard({
id,
name,
value,
origin,
category,
interest,
created_at,
}) {
return (
<div className="bg-white shadow-md rounded-lg p-4 relative">
<div className="flex justify-between items-center">
<Link href={`/investments/${id}`}>
<h3 className="investment-name text-lg font-semibold text-gray-700">
{name}
</h3>
</Link>
<p className="investment-value text-lg font-semibold text-gray-700">
{formatCurrency(value / 100)}
</p>
</div>
<div className="mt-4">
...
</div>
</div>
);
}
/codes/react/introduction/invest-app/src/components/InvestmentCard.jsx
import Link from 'next/link';
import { IconTrash } from '@tabler/icons-react';
import { formatCurrency, formatDate } from '@/lib/format';
export default function InvestmentCard({
id,
name,
value,
origin,
category,
interest,
created_at,
}) {
return (
<div className="bg-white shadow-md rounded-lg p-4 relative">
<div className="flex justify-between items-center">
<Link href={`/investments/${id}`}>
<h3 className="investment-name text-lg font-semibold text-gray-700">
{name}
</h3>
</Link>
<p className="investment-value text-lg font-semibold text-gray-700">
{formatCurrency(value / 100)}
</p>
</div>
<div className="mt-4">
...
</div>
</div>
);
}
Tratamento de Evento
$ npm install -d @iconify/react
$ npm install -d @iconify/react
/codes/react/introduction/invest-app/src/components/InvestmentCard.jsx
'use client';
import Link from 'next/link';
import { IconTrash } from '@tabler/icons-react';
import { formatCurrency, formatDate } from '@/lib/format';
export default function InvestmentCard({
id,
name,
value,
origin,
category,
interest,
created_at,
}) {
const handleDeleteInvestment = (name) => {
confirm(`Deseja remover ${name}?`);
};
return (
<div className="bg-white shadow-md rounded-lg p-4 relative">
<div className="flex justify-between items-center">
<Link href={`/investments/${id}`}>
<h3 className="investment-name text-lg font-semibold text-gray-700">
{name}
</h3>
</Link>
<p className="investment-value text-lg font-semibold text-gray-700">
{formatCurrency(value / 100)}
</p>
</div>
<div className="mt-4">
...
</div>
<div className="absolute bottom-4 right-4 inline-flex">
<IconTrash
size={20}
className="text-gray-400 hover:text-gray-500 cursor-pointer"
onClick={() => handleDeleteInvestment(name)}
/>
</div>
</div>
);
}
/codes/react/introduction/invest-app/src/components/InvestmentCard.jsx
'use client';
import Link from 'next/link';
import { IconTrash } from '@tabler/icons-react';
import { formatCurrency, formatDate } from '@/lib/format';
export default function InvestmentCard({
id,
name,
value,
origin,
category,
interest,
created_at,
}) {
const handleDeleteInvestment = (name) => {
confirm(`Deseja remover ${name}?`);
};
return (
<div className="bg-white shadow-md rounded-lg p-4 relative">
<div className="flex justify-between items-center">
<Link href={`/investments/${id}`}>
<h3 className="investment-name text-lg font-semibold text-gray-700">
{name}
</h3>
</Link>
<p className="investment-value text-lg font-semibold text-gray-700">
{formatCurrency(value / 100)}
</p>
</div>
<div className="mt-4">
...
</div>
<div className="absolute bottom-4 right-4 inline-flex">
<IconTrash
size={20}
className="text-gray-400 hover:text-gray-500 cursor-pointer"
onClick={() => handleDeleteInvestment(name)}
/>
</div>
</div>
);
}