Passo a passo na construção de exemplo em React
O que você precisa saber de React para falar que sabe algo, um um pouco
Biblioteca React criada para facilitar a criação de aplicativos para execução no navegador
Pré-requisitos
Para começar precisamos dos softwares
- Node, podemos verificar a instalação pelo comando
node -v
; - NPM, podemos verificar a instalação pelo comando
npm -v
; - Qualquer IDE com suporte a JavaScript recomendo VSCode.
Instalar a ferramenta de auxílio para configuração das ferramenta de construção
yarn global add create-react-app
# or
npm -g i create-react-app
Iniciar projeto pela ferramenta de auxílio
npx create-react-app medals-olympic
cd medals-olympic
yarn start
Projeto vai estar disponível em localhost:3000
Rotas
- Simulação de rotas;
- Redesenho do DOM.
Instalação da biblioteca react-router-dom
para controle de rotas
yarn add react-router-dom
# or
npm i react-router-dom
Criar o arquivo src/routes/Medals.jsx
dentro da pasta indicada, para com o caminho da rota de medalhas
import React from "react"
const Medals = () => {
return <h1>Medalhas</h1>
}
export default Medals
Criar o arquivo src/routes/Teams.jsx
para com o caminho da rota de times
import React from "react"
const Teams = () => {
return <h1>Time</h1>
}
export default Teams
Alterar o arquivo src/Apps.js
para aceitar as rotas criadas
import { BrowserRouter as Router, Route, Routes } from "react-router-dom"
import Medals from "./routes/Medals"
import Teams from "./routes/Teams"
function App() {
return (
<Router>
<div>
<Routes>
<Route path="/:team" element={<Teams />} />
<Route path="/" element={<Medals />} />
</Routes>
</div>
</Router>
)
}
export default App
Com o comando yarn start
podemos visualizar a resposta pelo localhost:3000 apresentando a rota medals e localhost:3000/sweden para apresentar a rota de teams, podemos substituir o sweden por qualquer conteúdo
Componentes
- Separação de responsabilidades;
- Propriedades de componentes;
- Desenho no DOM.
Criar o arquivo src/components/Header/index.jsx
com o conteúdo do que irá se apresentar no topo de todas as telas
import React from "react"
const Header = () => {
return (
<header>
<h1>Header</h1>
</header>
)
}
export default Header
Criar o arquivo src/components/Footer/index.jsx
com o conteúdo do que irá se apresentar no rodapé de todas as telas
import React from "react"
const Footer = () => {
return (
<footer>
<h1>Footer</h1>
</footer>
)
}
export default Footer
Criar o arquivo src/components/Main/index.jsx
, que irá encapsular as informações das rotas, destaque para o children
que é todo conteúdo dentro das tags do componente
import React from "react"
const Main = ({ children }) => {
return <main>{children}</main>
}
export default Main
Alterar o arquivo src/Apps.js
com destaque para a importação e adição do Header
e Footer
dentro da tag Router
import { BrowserRouter as Router, Route, Routes } from "react-router-dom"
import Footer from "./components/Footer"
import Header from "./components/Header"
import Main from "./components/Main"
import Medals from "./routes/Medals"
import Teams from "./routes/Teams"
function App() {
return (
<Router>
<Header />
<Main>
<Routes>
<Route path="/:team" element={<Teams />} />
<Route path="/" element={<Medals />} />
</Routes>
</Main>
<Footer />
</Router>
)
}
export default App
Com o comando yarn start
podemos visualizar a resposta pelo localhost:3000 com o conteúdo do header e footer em todos os caminhos
Estilos
- Construção das classes;
- Alteração do
head
.
Instalação da biblioteca styled-components
que facilitará o uso de CSS para os componentes
yarn add styled-components
# or
npm i styled-components
Criar o arquivo src/globalStyles.js
com o CSS Reset, setando as configurações padrão para estilos para o projeto
import { createGlobalStyle } from "styled-components"
const GlobalStyle = createGlobalStyle`
*,
*:before,
*:after {
margin: 0;
padding: 0;
outline: 0;
box-sizing: border-box;
}
html {
font-size: 62.5%;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
}
a,
a:hover,
a:visited {
text-decoration: none;
color: inherit;
}
`
export default GlobalStyle
Alterar o arquivo src/Apps.js
para adicionar a importação e o componente de GlobalStyle
import { BrowserRouter as Router, Route, Routes } from "react-router-dom"
import Footer from "./components/Footer"
import Header from "./components/Header"
import Main from "./components/Main"
import Medals from "./routes/Medals"
import Teams from "./routes/Teams"
import GlobalStyle from "./globalStyles"
function App() {
return (
<Router>
<GlobalStyle />
<Header />
<Main>
<Routes>
<Route path="/:team" element={<Teams />} />
<Route path="/" element={<Medals />} />
</Routes>
</Main>
<Footer />
</Router>
)
}
export default App
Criar o arquivo src/components/Header/styles.js
import styled from "styled-components"
export const Wrapper = styled.header`
height: 8rem;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
`
export const Content = styled.div`
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
padding-left: calc((100vw - 98rem) / 2);
`
export const Logo = styled.img`
height: 6rem;
`
export const Title = styled.h1`
margin-left: 2rem;
color: #444;
text-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25);
`
export const Back = styled.img`
height: 8rem;
`
Alterar o arquivo src/components/Header/index.jsx
import React from "react"
import { Wrapper, Content, Logo, Title, Back } from "./styles"
const Header = () => {
return (
<Wrapper>
<Content>
<Logo src="https://olympics.com/en/images/static/beijing-images/header/b2022-logo.svg" />
<Title>Medalhas Olimpiadas de Inverno 2022</Title>
</Content>
<Back src="https://olympics.com/images/static/beijing-images/header/b2022-mountains-right-v2.svg" />
</Wrapper>
)
}
export default Header
Criar o arquivo src/components/Footer/styles.js
import styled from "styled-components"
export const Wrapper = styled.footer`
height: 8rem;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
background: linear-gradient(90deg, #e8edf5 0, #fff 100%);
`
export const Credits = styled.h1`
text-align: center;
color: #444;
& a {
color: #1c50a1 !important;
&:hover {
text-decoration: underline;
}
}
`
Alterar o arquivo src/components/Footer/index.jsx
import React from "react"
import { Wrapper, Credits } from "./styles"
const Footer = () => {
return (
<Wrapper>
<Credits>
Desenvolvido com amor por{" "}
<a href="https://johnywalves.com.br/">Johny W. Alves</a>
</Credits>
</Wrapper>
)
}
export default Footer
Criar o arquivo src/components/Main/styles.js
import styled from "styled-components"
export const Wrapper = styled.main`
min-height: calc(100vh - 16rem);
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: center;
`
Alterar o arquivo src/components/Main/index.jsx
import React from "react"
import { Wrapper } from "./styles"
const Main = ({ children }) => {
return <Wrapper>{children}</Wrapper>
}
export default Main
Com o comando yarn start
podemos visualizar a resposta pelo localhost:3000
Listagem de informações (Medalhas)
Renomear o src/routes/Medals.jsx
para src/routes/Medals/index.jsx
import React from "react"
import Header from "./Header"
import Row from "./Row"
import { Wrapper } from "./styles"
const teams = [
{
team: "norway",
description: "Norway",
gold: 14,
silver: 7,
bronze: 8,
},
{
team: "germany",
description: "Germany",
gold: 10,
silver: 7,
bronze: 5,
},
{
team: "united-states-of-america",
description: "United States of America",
gold: 8,
silver: 8,
bronze: 5,
},
{
team: "sweden",
description: "Sweden",
gold: 7,
silver: 4,
bronze: 4,
},
{
team: "china",
description: "People`s Republic of China",
gold: 7,
silver: 4,
bronze: 2,
},
]
const Medals = () => {
return (
<Wrapper>
<Header />
{teams.map((team) => (
<Row key={team.team} {...team} />
))}
</Wrapper>
)
}
export default Medals
Criar o arquivo src/routes/Medal/styles.js
import styled from "styled-components"
export const Wrapper = styled.div`
min-height: calc(100vh - 16rem);
width: 100%;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: center;
`
Com o comando yarn start
podemos visualizar a resposta pelo localhost:3000
Cabeçalho do quadro de medalhas
Criar o arquivo src/routes/Medal/Header/index.jsx
import React from "react"
import { Wrapper, Team, Medals, Gold, Silver, Bronze, Total } from "./styles"
const MedalsHeader = () => {
return (
<Wrapper>
<Team>Time</Team>
<Medals>
<Gold />
<Silver />
<Bronze />
<Total />
</Medals>
</Wrapper>
)
}
export default MedalsHeader
Criar o arquivo src/routes/Medal/Header/styles.js
import styled from "styled-components"
export const Wrapper = styled.div`
font-size: 2rem;
font-weight: bold;
display: flex;
flex-direction: row;
color: #fff;
background-color: #444;
height: 5rem;
width: 100%;
margin: 0 0 0.5rem;
padding: 0 calc((100% - 88rem) / 2);
`
export const Team = styled.p`
display: flex;
align-items: center;
height: 5rem;
width: 50rem;
margin-left: 18rem;
`
export const Medals = styled.div`
display: flex;
flex-direction: row;
`
export const Gold = styled.div`
background-color: #fcc861;
border-radius: 50%;
height: 3rem;
width: 3rem;
margin: 1rem;
`
export const Silver = styled.div`
background-color: #e5e5e5;
border-radius: 50%;
height: 3rem;
width: 3rem;
margin: 1rem;
`
export const Bronze = styled.div`
background-color: #dcb386;
border-radius: 50%;
height: 3rem;
width: 3rem;
margin: 1rem;
`
export const Total = styled.div`
background-color: #fff;
border-radius: 50%;
height: 3rem;
width: 3rem;
margin: 1rem;
`
Com o comando yarn start
podemos visualizar a resposta pelo localhost:3000
Itens do quadro de medalhas
Criar o arquivo src/routes/Medal/Row/index.jsx
import React from "react"
import { Link } from "react-router-dom"
import { Wrapper, Flag, Description, Medal } from "./styles"
const MedalsRow = ({ team, description, gold, silver, bronze }) => {
return (
<Wrapper>
<Flag team={team} />
<Description>
<Link to={"/" + team}>{description}</Link>
</Description>
<Medal>{gold}</Medal>
<Medal>{silver}</Medal>
<Medal>{bronze}</Medal>
<Medal>{gold + silver + bronze}</Medal>
</Wrapper>
)
}
export default MedalsRow
Criar o arquivo src/routes/Medal/Row/styles.js
import styled from "styled-components"
export const Wrapper = styled.div`
height: 5rem;
font-size: 2rem;
display: flex;
flex-direction: row;
margin: 0.5rem 0;
`
export const Flag = styled.div`
background-image: url(${({ team }) =>
"https://www.countryflags.com/wp-content/uploads/" +
team +
"-flag-png-large.png"});
background-position: center;
background-size: contain;
background-repeat: no-repeat;
height: 5rem;
width: 18rem;
`
export const Description = styled.p`
display: flex;
align-items: center;
text-align: left;
height: 5rem;
width: 50rem;
&:hover {
text-decoration: underline;
}
`
export const Medal = styled.p`
display: flex;
justify-content: center;
align-items: center;
height: 5rem;
width: 5rem;
`
Com o comando yarn start
podemos visualizar a resposta pelo localhost:3000
Links no Cabeçalho da página
Criar o arquivo src/components/Header/index.js
import React from "react"
import { Link } from "react-router-dom"
import { Wrapper, Content, Logo, Title, Back } from "./styles"
const Header = () => {
return (
<Link to="/">
<Wrapper>
<Content>
<Logo src="https://olympics.com/en/images/static/beijing-images/header/b2022-logo.svg" />
<Title>Medalhas Olimpíadas de Inverno 2022</Title>
</Content>
<Back src="https://olympics.com/images/static/beijing-images/header/b2022-mountains-right-v2.svg" />
</Wrapper>
</Link>
)
}
export default Header
Com o comando yarn start
podemos visualizar a resposta pelo localhost:3000
Listagem de informações (Times)
Vamos listar o detalhe dos países de acordo com o caminho informado
Renomear o src/routes/Teams.jsx
para src/routes/Teams/index.jsx
e mudar o conteúdo para adicionar a lista de países, ler a rota e apresentar as informações pela instrução
import React, { useMemo } from "react"
import { useParams } from "react-router-dom"
import { Wrapper, Flag, Name, Description } from "./styles"
const teams = [
{
id: "norway",
name: "Norway",
description:
"The Norwegian flag is a white-fimbriated blue Nordic cross on a red field. The used colors in the flag are blue, red, white. The proportion of the Norwegian flag is 8:11. The Flag of Norway was adopted in 1821. The first use of the current flag design was in 1821. The last change to the current Norwegian flag design was in 1899.",
},
{
id: "germany",
name: "Germany",
description:
"The German flag is a horizontal triband. The used colors in the flag are red, yellow, black. The proportion of the German flag is 3:5. The Flag of Germany was adopted in 1918. The first use of the current flag design was in 1848. The last change to the current German flag design was in 1949.",
},
{
id: "united-states-of-america",
name: "United States of America",
description:
"The United States flag – USA flag – American flag is a flag with thirteen horizontal stripes with 50 white stars in a blue field. The used colors in the flag are blue, red, white. The proportion of the United States flag – USA flag – American flag is 10:19. The Flag of the United States was adopted in 1960. The first use of the current flag design was in 1818. The last change to the current United States flag design was in 1960.",
},
{
id: "sweden",
name: "Sweden",
description:
"The Swedish flag is a one coloured field with a cross. The used colors in the flag are blue, yellow. The proportion of the Swedish flag is 5:8. The Flag of Sweden was adopted in 1906. The first use of the current flag design was in 1562. The last change to the current Swedish flag design was in 1906.",
},
{
id: "china",
name: "People`s Republic of China",
description:
"The Chinese flag is a solid flag with four small stars and one bigger star in the upper left corner. The used colors in the flag are red, yellow. The proportion of the Chinese flag is 2:3. The Flag of China was adopted in 1949. The first use of the current flag design was in 1949.",
},
]
const Teams = () => {
const { team } = useParams()
const { id, name, description } = useMemo(() => {
const current = teams.find(({ id: id_team }) => id_team === team)
if (current) {
return current
}
return { id: "", name: "", description: "" }
}, [team])
return (
<Wrapper>
<Name>{name}</Name>
<Flag id={id} />
<Description>{description}</Description>
</Wrapper>
)
}
export default Teams
Criar o arquivo com estilo src/routes/Teams/styles.js
import styled from "styled-components"
export const Wrapper = styled.div`
display: flex;
flex-direction: column;
align-items: center;
width: 88rem;
padding-top: 2rem;
`
export const Name = styled.h1`
font-size: 3rem;
margin: 1rem 0;
`
export const Flag = styled.div`
background-image: url(${({ id }) =>
"https://www.countryflags.com/wp-content/uploads/" +
id +
"-flag-png-large.png"});
background-position: center;
background-size: contain;
background-repeat: no-repeat;
height: 18rem;
width: 30rem;
margin: 1rem 0;
`
export const Description = styled.p`
font-size: 2rem;
margin: 2rem 0 0;
`
Com o comando yarn start
podemos visualizar a resposta pelo localhost:3000
API
- Explicação da biblioteca
json-server
; - Explicação da biblioteca
concurrently
;
yarn add json-server concurrently
# or
npm i json-server concurrently
Adicionar no package.json
em scripts
// ...
"scripts": {
// ...
"server": "npx json-server --watch db.json --port 8000",
"dev": "concurrently \"yarn start\" \"yarn server\""
}
// ...
Criar o arquivo db.json
na raiz, que irá servir como nosso banco de dados inicial
{
"medals": [
{
"team": "norway",
"description": "Norway",
"gold": 14,
"silver": 7,
"bronze": 8
},
{
"team": "germany",
"description": "Germany",
"gold": 10,
"silver": 7,
"bronze": 5
},
{
"team": "united-states-of-america",
"description": "United States of America",
"gold": 8,
"silver": 8,
"bronze": 5
},
{
"team": "sweden",
"description": "Sweden",
"gold": 7,
"silver": 4,
"bronze": 4
},
{
"team": "china",
"description": "People`s Republic of China",
"gold": 7,
"silver": 4,
"bronze": 2
}
],
"teams": [
{
"id": "norway",
"name": "Norway",
"description": "The Norwegian flag is a white-fimbriated blue Nordic cross on a red field. The used colors in the flag are blue, red, white. The proportion of the Norwegian flag is 8:11. The Flag of Norway was adopted in 1821. The first use of the current flag design was in 1821. The last change to the current Norwegian flag design was in 1899."
},
{
"id": "germany",
"name": "Germany",
"description": "The German flag is a horizontal triband. The used colors in the flag are red, yellow, black. The proportion of the German flag is 3:5. The Flag of Germany was adopted in 1918. The first use of the current flag design was in 1848. The last change to the current German flag design was in 1949."
},
{
"id": "united-states-of-america",
"name": "United States of America",
"description": "The United States flag – USA flag – American flag is a flag with thirteen horizontal stripes with 50 white stars in a blue field. The used colors in the flag are blue, red, white. The proportion of the United States flag – USA flag – American flag is 10:19. The Flag of the United States was adopted in 1960. The first use of the current flag design was in 1818. The last change to the current United States flag design was in 1960."
},
{
"id": "sweden",
"name": "Sweden",
"description": "The Swedish flag is a one coloured field with a cross. The used colors in the flag are blue, yellow. The proportion of the Swedish flag is 5:8. The Flag of Sweden was adopted in 1906. The first use of the current flag design was in 1562. The last change to the current Swedish flag design was in 1906."
},
{
"id": "china",
"name": "People`s Republic of China",
"description": "The Chinese flag is a solid flag with four small stars and one bigger star in the upper left corner. The used colors in the flag are red, yellow. The proportion of the Chinese flag is 2:3. The Flag of China was adopted in 1949. The first use of the current flag design was in 1949."
}
]
}
Alterar o src/routes/Medals/index.jsx
, para fazer a chamada na API e gerenciar os estados com a resposta
import React, { useState, useEffect } from "react"
import Header from "./Header"
import Row from "./Row"
import { Wrapper } from "./styles"
const Medals = () => {
const [medals, setMedals] = useState([])
useEffect(() => {
fetch("http://localhost:8000/medals")
.then((response) => response.json())
.then((data) => setMedals(data))
}, [])
return (
<Wrapper>
<Header />
{medals.map((team) => (
<Row key={team.team} {...team} />
))}
</Wrapper>
)
}
export default Medals
Alterar o routes/Teams/index.jsx
, para fazer a chamada na API e gerenciar os estados com a resposta
import React, { useState, useEffect } from "react"
import { useParams } from "react-router-dom"
import { Wrapper, Flag, Name, Description } from "./styles"
const Teams = () => {
const { team } = useParams()
const [current, setCurrent] = useState()
useEffect(() => {
fetch(`http://localhost:8000/teams?id=${team}`)
.then((response) => response.json())
.then((data) => data && data.length > 0 && setCurrent(data[0]))
}, [team])
if (!current) {
return (
<Wrapper>
<Name>Time não encontrado</Name>
</Wrapper>
)
}
return (
<Wrapper>
<Name>{current.name}</Name>
<Flag id={current.id} />
<Description>{current.description}</Description>
</Wrapper>
)
}
export default Teams
Com o comando yarn dev
podemos visualizar a resposta pelo localhost:3000