Projeto inicial desenvolvido para a atividade prática da disciplina de Single Page Application (SPA).
Este repositório funciona como um laboratório de fundamentos do React, no qual diferentes conceitos serão implementados progressivamente durante a aula.
A estrutura inicial do projeto, os assets, os componentes e o CSS já estão disponíveis. Entretanto, a lógica dos componentes foi propositalmente removida.
O objetivo é que cada funcionalidade seja construída conforme os conceitos forem apresentados.
Nesta atividade vamos revisar e aplicar alguns dos principais fundamentos utilizados no desenvolvimento de aplicações React.
Ao final do exercício, você deverá compreender como uma aplicação React pode ser construída através da combinação de:
Dados
↓
Componentes
↓
Props
↓
State
↓
Eventos
↓
Renderização
↓
Interface
A aplicação será desenvolvida como um conjunto de pequenos exemplos independentes.
Cada componente terá uma responsabilidade específica e será utilizado para demonstrar um conceito.
O objetivo não é copiar uma aplicação pronta.
Implemente cada componente conforme o conceito for apresentado durante a aula.
O projeto inicial contém:
- estrutura básica do React;
- arquivos dos componentes;
- CSS completo da aplicação;
- imagens utilizadas no exercício;
- comentários dentro dos componentes;
- estrutura inicial do
App.js.
Os arquivos localizados em:
src/components
possuem comentários indicando:
- a responsabilidade do componente;
- o conceito React relacionado;
- o comportamento esperado;
- as classes CSS disponíveis;
- os pontos que deverão ser implementados.
A lógica principal deverá ser desenvolvida pelo aluno.
Durante o desenvolvimento serão revisados os seguintes conceitos:
- JSX;
- Components;
- Props;
- Destructuring;
useState;- eventos;
- renderização condicional;
- renderização de listas;
map();key;filter();- atualização de arrays em State;
- reutilização de componentes;
- Fragment;
children;- passagem de funções através de props;
- lifting state up;
- manipulação de assets;
- organização básica de uma aplicação React.
src/
├── assets/
│ └── city.jpg
│
├── components/
│ ├── ManageData.js
│ ├── ListRender.js
│ ├── ConditionalRender.js
│ ├── ShowUserName.js
│ ├── CarDetails.js
│ ├── Fragment.js
│ ├── Container.js
│ ├── ExecuteFunction.js
│ ├── MessageState.js
│ └── ChangeMessageState.js
│
├── App.js
├── App.css
├── index.js
└── index.css
public/
└── img1.jpg
É o componente principal da aplicação.
Ele será responsável por integrar os diferentes exemplos desenvolvidos durante a aula.
O fluxo será semelhante a:
App
│
├── ManageData
├── ListRender
├── ConditionalRender
├── ShowUserName
├── CarDetails
├── Container
├── ExecuteFunction
├── MessageState
└── ChangeMessageState
Não desenvolva todo o App.js de uma única vez.
Cada componente deverá ser adicionado conforme o conteúdo for estudado.
Será utilizado para estudar:
Variável JavaScript
x
State do React
O objetivo é perceber que alterar uma variável JavaScript comum não significa necessariamente atualizar a interface.
Aqui será introduzido:
useState()Responsável pelos conceitos relacionados a listas.
Serão utilizados:
map()
filter()
key
useState()O componente deverá evoluir de uma lista simples para uma coleção de objetos.
Será utilizado para estudar como React decide se determinado elemento deve ou não aparecer na interface.
Serão utilizados exemplos envolvendo:
&&e:
condicao ? valorA : valorBPrimeira demonstração de comunicação entre componentes utilizando:
Props
Um componente receberá informações enviadas pelo componente pai.
Será utilizado para estudar:
- props;
- destructuring;
- reutilização de componentes;
- objetos;
- geração dinâmica de componentes.
Demonstra como retornar múltiplos elementos sem criar um elemento HTML adicional apenas para agrupá-los.
Será utilizado para demonstrar:
props.childrenEsse conceito permite criar componentes capazes de envolver diferentes tipos de conteúdo.
Será utilizado para demonstrar que props não transportam apenas strings ou números.
Também é possível enviar:
Funções
de um componente para outro.
Será responsável por exibir uma informação armazenada em um componente superior.
Será responsável por disparar uma alteração no State que pertence ao componente pai.
Esses dois componentes serão utilizados para estudar:
Lifting State Up
Certifique-se de possuir o Node.js instalado.
No terminal, entre na pasta do projeto.
Instale as dependências:
npm installDepois execute:
npm startA aplicação deverá ficar disponível em:
http://localhost:3000
JSX é a sintaxe utilizada pelo React para descrever a interface.
Sua aparência é semelhante ao HTML:
<h1>Hello React</h1>Porém JSX permite utilizar JavaScript dentro da interface.
Para isso utilizamos:
{ }
Exemplo:
const course = "React";
return (
<h2>Estudando {course}</h2>
);O valor da variável será inserido no JSX.
Fluxo:
JavaScript
↓
Expressão
↓
{ }
↓
JSX
↓
Interface
JSX não é exatamente HTML.
Por exemplo, para adicionar uma classe CSS utilizamos:
className="card"e não:
class="card"React — Writing Markup with JSX:
https://react.dev/learn/writing-markup-with-jsx
JavaScript in JSX:
https://react.dev/learn/javascript-in-jsx-with-curly-braces
Componentes são os principais blocos utilizados para construir interfaces React.
Uma página pode ser dividida em partes menores:
Página
│
├── Header
├── Content
│ ├── Card
│ ├── Card
│ └── Card
│
└── Footer
Cada bloco pode se tornar um componente.
Um componente React normalmente é representado por uma função.
Exemplo genérico:
const Welcome = () => {
return (
<div>
<h2>Welcome</h2>
</div>
);
};
export default Welcome;Depois ele pode ser utilizado em outro componente:
<Welcome />Componentes ajudam a criar aplicações:
- organizadas;
- reutilizáveis;
- mais fáceis de manter;
- divididas em responsabilidades menores.
Em vez de possuir um único arquivo com centenas de linhas, podemos dividir a interface.
Interface grande
↓
Divisão
↓
Componentes menores
↓
Responsabilidades específicas
Your First Component:
https://react.dev/learn/your-first-component
Importing and Exporting Components:
https://react.dev/learn/importing-and-exporting-components
Props permitem enviar informações entre componentes.
O fluxo normalmente ocorre assim:
Componente Pai
│
│ props
▼
Componente Filho
Exemplo conceitual:
<User name="Alex" />O componente filho pode receber essa informação:
const User = (props) => {
return <p>{props.name}</p>;
};Props permitem reutilizar o mesmo componente com informações diferentes.
<User name="Alex" />
<User name="Maria" />
<User name="John" />O componente é o mesmo.
O que muda são os dados.
User
/ | \
/ | \
Alex Maria John
Props são utilizadas para comunicar dados do componente pai para o filho.
O componente filho não deve alterar diretamente as props recebidas.
Passing Props to a Component:
https://react.dev/learn/passing-props-to-a-component
Props são objetos JavaScript.
Por isso podemos utilizar destructuring.
Em vez de:
const User = (props) => {
return <p>{props.name}</p>;
};podemos escrever:
const User = ({ name }) => {
return <p>{name}</p>;
};Com várias informações:
const Product = ({ name, price, category }) => {
// ...
};Isso torna o código mais enxuto quando sabemos quais propriedades serão utilizadas.
Props permitem receber dados.
State permite que um componente lembre informações que podem mudar durante a execução da aplicação.
Para trabalhar com State utilizaremos:
useState()Exemplo conceitual:
import { useState } from "react";
const Example = () => {
const [value, setValue] = useState(0);
return (
<button onClick={() => setValue(value + 1)}>
{value}
</button>
);
};Aqui:
value
representa o valor atual.
Enquanto:
setValue
é utilizado para atualizar esse valor.
Fluxo:
Usuário executa uma ação
↓
setValue(...)
↓
React atualiza o State
↓
Componente renderiza novamente
↓
Interface apresenta o novo valor
Esse processo é fundamental para aplicações interativas.
State: A Component's Memory:
https://react.dev/learn/state-a-components-memory
Considere uma variável JavaScript comum:
let value = 10;Podemos alterar seu valor:
value = 20;Entretanto React não utiliza essa alteração automaticamente como um sinal para atualizar a interface.
Com State:
const [value, setValue] = useState(10);a atualização ocorre através da função:
setValue(20);Isso informa ao React que existe uma alteração relevante para a interface.
Fluxo conceitual:
Variável comum
value = 20
↓
JavaScript alterou o valor
↓
React não necessariamente renderiza novamente
Com State:
setValue(20)
↓
State atualizado
↓
React renderiza novamente
↓
Interface atualizada
React permite responder às ações realizadas pelo usuário.
Alguns eventos comuns:
onClick
onChange
onSubmit
onMouseEnter
onMouseLeave
Nesta atividade utilizaremos principalmente:
onClickExemplo:
const showMessage = () => {
console.log("Button clicked");
};
<button onClick={showMessage}>
Execute
</button>Observe que passamos:
showMessagee não:
showMessage()Caso contrário, a função seria executada durante a renderização.
Fluxo:
Usuário
↓
Clique
↓
onClick
↓
Função
↓
Ação
Responding to Events:
https://react.dev/learn/responding-to-events
Aplicações frequentemente trabalham com coleções de informações.
Exemplo:
const technologies = [
"React",
"JavaScript",
"HTML",
"CSS"
];Para transformar esses dados em JSX podemos utilizar:
map()Exemplo genérico:
<ul>
{technologies.map((technology) => (
<li>{technology}</li>
))}
</ul>O fluxo será:
Array
↓
map()
↓
cada item
↓
JSX
↓
lista renderizada
Aplicações reais normalmente trabalham com objetos.
Exemplo:
const users = [
{
id: 1,
name: "Ana"
},
{
id: 2,
name: "Carlos"
}
];Podemos acessar:
user.id
user.namee gerar componentes dinamicamente.
A ideia geral será:
Array de objetos
↓
map()
↓
Objeto atual
↓
Props
↓
Componente
Esse padrão será utilizado em diferentes momentos da atividade.
Rendering Lists:
https://react.dev/learn/rendering-lists
Ao criar uma lista de elementos React, cada elemento deve possuir uma identificação.
Exemplo conceitual:
items.map((item) => (
<li key={item.id}>
{item.name}
</li>
))A key ajuda React a identificar cada item durante atualizações da interface.
Quando possível, utilize identificadores únicos existentes nos próprios dados:
id
em vez da posição do elemento.
Preferível:
key={item.id}Evite utilizar índice quando existe um identificador estável:
key={index}Principalmente quando:
- itens podem ser removidos;
- itens podem mudar de posição;
- novos elementos podem ser adicionados.
Rendering Lists:
https://react.dev/learn/rendering-lists
Não devemos modificar diretamente arrays armazenados no State.
Em vez disso, criamos um novo array.
Uma das funções utilizadas para isso é:
filter()Exemplo JavaScript:
const numbers = [1, 2, 3, 4];
const filteredNumbers = numbers.filter(
(number) => number !== 3
);Resultado:
[1, 2, 4]Aplicado conceitualmente ao React:
State atual
↓
filter()
↓
novo array
↓
setState()
↓
React renderiza novamente
Updating Arrays in State:
https://react.dev/learn/updating-arrays-in-state
Nem todos os elementos precisam aparecer o tempo inteiro.
Podemos utilizar condições para decidir o que será exibido.
Exemplo:
{isLogged && <p>Usuário conectado</p>}Se:
isLogged === trueo elemento será renderizado.
Quando existem dois possíveis resultados:
{isLogged ? (
<p>Usuário conectado</p>
) : (
<p>Faça login</p>
)}Fluxo:
Condição
↓
true ──────→ elemento A
false ─────→ elemento B
Conditional Rendering:
https://react.dev/learn/conditional-rendering
Um dos principais objetivos da componentização é reutilizar estruturas.
Considere um componente genérico:
Card
Ele pode receber diferentes dados:
Card
├── Produto A
├── Produto B
└── Produto C
Em vez de copiar o mesmo JSX várias vezes, podemos reutilizar:
<Card ... />
<Card ... />
<Card ... />Depois podemos evoluir para:
Array
↓
map()
↓
<Card />
Esse conceito será praticado com CarDetails.
Um componente React precisa retornar uma estrutura válida.
Às vezes queremos retornar vários elementos sem criar uma <div> apenas para agrupá-los.
Podemos utilizar:
<>
<h2>Título</h2>
<p>Descrição</p>
</>Esse recurso é chamado:
Fragment
Outra forma:
import { Fragment } from "react";
<Fragment>
...
</Fragment>O Fragment não cria um elemento adicional no HTML final.
Fragment:
https://react.dev/reference/react/Fragment
Um componente pode receber conteúdo entre sua abertura e fechamento.
Exemplo:
<Box>
<p>Conteúdo</p>
</Box>O conteúdo:
<p>Conteúdo</p>será recebido pelo componente através de:
childrenExemplo conceitual:
const Box = ({ children }) => {
return (
<div className="box">
{children}
</div>
);
};Isso permite criar componentes extremamente reutilizáveis.
Container
│
└── children
│
├── texto
├── imagem
├── botão
└── outro componente
Passing Props to a Component:
https://react.dev/learn/passing-props-to-a-component
Props não transportam apenas dados.
Também podemos enviar funções.
Fluxo:
Componente Pai
│
│ function
▼
Componente Filho
│
│ onClick
▼
Executa função criada no Pai
Exemplo conceitual:
const Parent = () => {
const executeAction = () => {
console.log("Executando no componente pai");
};
return (
<Child action={executeAction} />
);
};No filho:
const Child = ({ action }) => {
return (
<button onClick={action}>
Execute
</button>
);
};Esse padrão é muito utilizado para comunicação entre componentes.
Imagine dois componentes:
MessageState
ChangeMessageState
Um precisa mostrar uma mensagem.
Outro precisa alterar a mensagem.
Se cada componente criar seu próprio State:
MessageState
└── message A
ChangeMessageState
└── message B
teremos dois estados independentes.
A solução é mover o State para o componente pai.
App
│
message state
/ \
/ \
▼ ▼
MessageState ChangeMessageState
│ │
exibe mensagem altera mensagem
Essa estratégia é conhecida como:
Lifting State Up
O State sobe para o ancestral comum entre os componentes.
Depois:
App
│
├── envia o valor por props
│
└── envia a função de atualização por props
Sharing State Between Components:
https://react.dev/learn/sharing-state-between-components
Nesta atividade serão utilizadas duas estratégias diferentes.
Exemplo:
public/
└── img1.jpg
O arquivo pode ser referenciado por um caminho público:
<img
src="/img1.jpg"
alt="Example"
/>Exemplo:
src/
└── assets/
└── city.jpg
Nesse caso o arquivo normalmente será importado:
import cityImage from "./assets/city.jpg";Depois utilizado:
<img
src={cityImage}
alt="City"
/>Nesta atividade utilizaremos as duas estratégias justamente para comparar o comportamento.
Durante a aula o projeto deverá evoluir aproximadamente desta forma:
1. JSX estático
↓
2. Componentes
↓
3. Props
↓
4. State
↓
5. Eventos
↓
6. Arrays
↓
7. map()
↓
8. Renderização dinâmica
↓
9. filter()
↓
10. Componentes reutilizáveis
↓
11. Funções por props
↓
12. Lifting State Up
O objetivo é perceber que aplicações React são construídas através da composição progressiva desses conceitos.
A implementação deverá seguir a sequência abaixo.
Objetivos:
- revisar JSX;
- importar CSS;
- utilizar imagens;
- comparar
publicesrc/assets.
Objetivos:
- comparar variável comum e State;
- introduzir
useState; - entender re-renderização.
Objetivos:
- arrays;
map();- objetos;
key;filter();- arrays em State.
Objetivos:
- condições;
&&;- operador ternário.
Objetivos:
- props;
- comunicação pai → filho.
Objetivos:
- props;
- destructuring;
- reutilização;
- componentes gerados através de arrays.
Objetivos:
- evitar wrappers HTML desnecessários;
- utilizar Fragment.
Objetivos:
- composição;
children;- reutilização de estruturas.
Objetivos:
- funções em props;
- comunicação entre componentes;
- eventos.
Objetivos:
- State compartilhado;
- funções através de props;
- lifting state up.
Ao finalizar:
- revise os imports;
- remova código não utilizado;
- verifique warnings;
- verifique erros no console;
- confira as
key; - revise os nomes;
- confira a organização dos componentes.
Não tente implementar tudo antes de testar.
Utilize ciclos curtos:
Criar
↓
Executar
↓
Testar
↓
Verificar console
↓
Corrigir
↓
Commit
↓
Próxima etapa
Procure criar commits pequenos e relacionados com a evolução do projeto.
Exemplos:
git commit -m "feat: create manage data example"git commit -m "feat: implement list rendering example"git commit -m "feat: add conditional rendering example"git commit -m "feat: add props examples"git commit -m "feat: add reusable car component"git commit -m "feat: demonstrate children composition"git commit -m "feat: demonstrate function props"git commit -m "feat: implement lifting state up example"Evite desenvolver toda a atividade e gerar apenas um commit no final.
Durante o desenvolvimento, tente responder:
-
Qual a diferença entre uma variável JavaScript e um State?
-
O que acontece quando chamamos uma função de atualização do State?
-
Por que React renderiza novamente um componente?
-
O que são props?
-
Qual é o sentido do fluxo:
Pai → Filho
em props?
-
Por que componentes devem ser reutilizáveis?
-
Qual é o objetivo do
map()? -
Por que elementos gerados por
map()precisam dekey? -
Qual a vantagem de utilizar
filter()para remover elementos? -
Qual a diferença entre:
props.namee:
{ name }-
Para que serve Fragment?
-
O que representa
children? -
Podemos enviar funções através de props?
-
Por que mover um State para o componente pai?
-
O que significa lifting state up?
-
Quando um dado pode ser calculado diretamente, precisamos criar outro State?
Não implemente o
App.jsfinal antes de desenvolver os componentes individualmente.
A evolução da atividade deve ser visível.
Hardcoded
↓
Dados
↓
State
↓
Componentes
↓
Props
↓
Componentes reutilizáveis
↓
Comunicação entre componentes
O objetivo principal desta atividade não é apenas fazer a aplicação funcionar.
O objetivo é conseguir explicar:
por que o código funciona
e:
qual problema cada conceito React resolve.
React — Learn
Describing the UI:
https://react.dev/learn/describing-the-ui
Writing Markup with JSX:
https://react.dev/learn/writing-markup-with-jsx
JavaScript in JSX with Curly Braces:
https://react.dev/learn/javascript-in-jsx-with-curly-braces
Your First Component:
https://react.dev/learn/your-first-component
Importing and Exporting Components:
https://react.dev/learn/importing-and-exporting-components
Passing Props to a Component:
https://react.dev/learn/passing-props-to-a-component
State: A Component's Memory:
https://react.dev/learn/state-a-components-memory
Responding to Events:
https://react.dev/learn/responding-to-events
Rendering Lists:
https://react.dev/learn/rendering-lists
Conditional Rendering:
https://react.dev/learn/conditional-rendering
Updating Arrays in State:
https://react.dev/learn/updating-arrays-in-state
Sharing State Between Components:
https://react.dev/learn/sharing-state-between-components
React Fragment:
https://react.dev/reference/react/Fragment
Ao terminar a atividade você deverá compreender o fluxo fundamental de uma aplicação React:
Data
↓
Components
↓
Props / State
↓
Events
↓
State Update
↓
Re-render
↓
Updated UI
Esses conceitos serão utilizados como base para aplicações React mais completas nas próximas aulas.