Roteiro de Atividade Prática
Nome: Turma:
.
Atividade: Otimização de performance em React
Você foi encarregado de otimizar uma aplicação React que exibe uma lista de
usuários e permite adicionar novos. A aplicação está enfrentando problemas de
performance, pois a lista cresce com o tempo e as renderizações estão se
tornando lentas.
Situação fictícia produzida pela SEDUC-SP.
Para resolver isso, aplicaremos as técnicas de Memoization, Pure
Components e Virtualização de Listas. O objetivo é melhorar a experiência
do usuário tornando a aplicação mais eficiente.
Passos Iniciais
1. Instalar o [Link] e npm: se você ainda não tem o [Link] instalado,
precisa baixá-lo e instalá-lo do site oficial (Acesso em: 6 dez. 2024). O
npm é instalado automaticamente com o [Link].
2. Criar um novo projeto React: para iniciar um novo projeto React, ele
pode usar o comando npx create-react-app. No terminal, você deve
executar:
npx create-react-app performance-optimization
3. Navegar para o diretório do projeto:
cd performance-optimization
4. Instalar as dependências necessárias:
O aluno deve instalar a biblioteca react-window para a virtualização da
lista:
npm install react-window
5. Instalar o React Router:
Como a aplicação pode usar o roteamento para diferentes componentes
(Home, About), é necessário instalar react-router-dom:
npm install react-router-dom
6. Estrutura de componentes:
[SIS] [U2] [C3]
1 / 15
O aluno deve criar os componentes [Link] e [Link] dentro de uma
pasta components. Para isso, ele pode criar os arquivos manualmente ou
com os seguintes comandos no terminal:
mkdir src/components
7. Adicionar o código base:
O código fornecido na atividade já está estruturado, mas o aluno precisa
garantir que ele funcione adequadamente e que as dependências (como
React Router e react-window) estejam integradas.
Executar a aplicação
Após seguir os passos anteriores, o aluno deve iniciar o servidor de
desenvolvimento com o comando:
npm start
Aplicação base (No arquivo [Link] em src)
Abaixo está o código de uma aplicação que renderiza uma lista de usuários
e permite adicionar mais usuários. Vamos usá-lo como ponto de partida:
import React, { useState } from 'react';
function App() {
const [users, setUsers] = useState(['Alice', 'Bob', 'Charlie']);
const [newUser, setNewUser] = useState('');
const addUser = () => {
setUsers([...users, newUser]);
setNewUser('');
};
return (
<div>
<h1>Lista de Usuários</h1>
<input
type="text"
value={newUser}
onChange={(e) => setNewUser([Link])}
placeholder="Adicionar usuário"
/>
<button onClick={addUser}>Adicionar</button>
<ul>
{[Link]((user, index) => (
<li key={index}>{user}</li>
))}
</ul>
</div>
);
[SIS] [U2] [C3]
2 / 15
}
export default App;
Problema:
À medida que a lista cresce, a aplicação fica mais lenta, pois a renderização de
toda a lista acontece toda vez que um novo usuário é adicionado, mesmo que
apenas um item mude. Vamos aplicar três técnicas para otimizar essa
aplicação.
Passo 1: Memoization com [Link]()
Objetivo: Evitar renderizações desnecessárias dos itens da lista.
Problema: No código atual, toda vez que o estado da aplicação muda (como
ao adicionar um usuário), todos os itens da lista são renderizados novamente,
mesmo que não tenham mudado.
Solução: Usar [Link]() para memoizar cada item da lista, de modo que
ele só seja re-renderizado quando suas props (o nome do usuário) mudarem.
Implementação:
Primeiro, extraia o item da lista para um componente separado e use o
[Link]().
const UserItem = [Link](({ user }) => {
return <li>{user}</li>;
});
function App() {
const [users, setUsers] = useState(['Alice', 'Bob', 'Charlie']);
const [newUser, setNewUser] = useState('');
const addUser = () => {
setUsers([...users, newUser]);
setNewUser('');
};
return (
<div>
<h1>Lista de Usuários</h1>
<input
type="text"
value={newUser}
onChange={(e) => setNewUser([Link])}
placeholder="Adicionar usuário"
/>
[SIS] [U2] [C3]
3 / 15
<button onClick={addUser}>Adicionar</button>
<ul>
{[Link]((user, index) => (
<UserItem key={index} user={user} />
))}
</ul>
</div>
);
}
Explicação:
[Link]() faz com que o componente UserItem só seja re-
renderizado quando suas props mudam. Agora, ao adicionar um novo
usuário, apenas o item novo é renderizado, enquanto os outros
permanecem inalterados.
Passo 2: Pure Components
Objetivo: Usar Pure Components para evitar renderizações desnecessárias em
componentes de classe.
Problema: Se tivermos algum componente de classe na aplicação, como o
formulário de adição de usuários, ele pode estar sendo re-renderizado mesmo
quando suas props e estado não mudam.
Solução: Transformar o componente de classe em um Pure Component para
que ele só se re-renderize se houver mudanças nas props ou no estado.
Implementação: Neste exemplo, vamos transformar o botão de adicionar em
um Pure Component.
class AddUserButton extends [Link] {
render() {
return <button onClick={[Link]}>Adicionar</button>;
}
}
function App() {
const [users, setUsers] = useState(['Alice', 'Bob', 'Charlie']);
const [newUser, setNewUser] = useState('');
const addUser = () => {
setUsers([...users, newUser]);
setNewUser('');
};
[SIS] [U2] [C3]
4 / 15
return (
<div>
<h1>Lista de Usuários</h1>
<input
type="text"
value={newUser}
onChange={(e) => setNewUser([Link])}
placeholder="Adicionar usuário"
/>
<AddUserButton onClick={addUser} />
<ul>
{[Link]((user, index) => (
<UserItem key={index} user={user} />
))}
</ul>
</div>
);
}
Explicação:
[Link] verifica se as props ou o estado do componente
mudaram antes de re-renderizar. Isso impede que o botão seja re-
renderizado toda vez que a lista de usuários for atualizada.
Passo 3: Virtualização de listas com react-window
Objetivo: Melhorar a performance ao renderizar uma lista grande, carregando
apenas os itens visíveis na tela.
Problema: Com muitos usuários na lista, a renderização de todos os itens ao
mesmo tempo pode ser lenta e ineficiente.
Solução: Usar a biblioteca react-window para virtualizar a lista e renderizar
apenas os itens visíveis na tela.
Implementação: Instale a biblioteca react-window: No prompt ou terminal:
npm install react-window
[SIS] [U2] [C3]
5 / 15
Substitua a renderização da lista por um componente virtualizado:
import { FixedSizeList as List } from 'react-window';
const UserItem = [Link](({ user }) => {
return <div>{user}</div>;
});
function App() {
const [users, setUsers] = useState(['Alice', 'Bob', 'Charlie']);
const [newUser, setNewUser] = useState('');
const addUser = () => {
setUsers([...users, newUser]);
setNewUser('');
};
return (
<div>
<h1>Lista de Usuários</h1>
<input
type="text"
value={newUser}
onChange={(e) => setNewUser([Link])}
placeholder="Adicionar usuário"
/>
<AddUserButton onClick={addUser} />
<List
height={150}
itemCount={[Link]}
itemSize={35}
width={300}
>
{({ index, style }) => (
<div style={style}>
<UserItem user={users[index]} />
</div>
)}
</List>
</div>
);
}
Explicação:
react-window permite renderizar apenas os itens visíveis da lista,
economizando recursos. No exemplo, a lista renderiza apenas os itens
[SIS] [U2] [C3]
6 / 15
que cabem em uma altura de 150px, carregando mais à medida que o
usuário rola a tela.
Não esqueça de entregar e registrar na plataforma:
Aplicação React otimizada usando [Link](), Pure Components e
react-window.
Relatório explicando as melhorias de performance observadas antes e
depois das otimizações.
* Instalar o [Link] e npm: Se você ainda não tem o [Link] instalado,
precisa baixá-lo e instalá-lo do site oficial (Acesso em: 6 dez. 2024). O
npm é instalado automaticamente com o [Link].
* Verificação: Para confirmar a instalação, abra o terminal e digite
node -v e npm -v.
* Criar um novo projeto React: Para iniciar um novo projeto React,
utilize o comando npx create-react-app. No terminal, você deve
executar:
npx create-react-app performance-optimization
* Navegar para o diretório do projeto:
cd performance-optimization
* Instalar as dependências necessárias: O aluno deve instalar a
biblioteca react-window para a virtualização da lista:
npm install react-window
* Instalar o React Router: Como a aplicação pode usar o roteamento
para diferentes componentes (Home, About), é necessário instalar
react-router-dom:
npm install react-router-dom
* Observação: Embora o react-router-dom tenha sido mencionado, o
código base fornecido para otimização não o utiliza diretamente. É
importante notar isso para não gerar confusão no aluno sobre sua
[SIS] [U2] [C3]
7 / 15
aplicação imediata nesta atividade específica. No entanto, é uma boa
prática para projetos React mais complexos.
* Estrutura de componentes: O aluno deve criar os componentes
[Link] e [Link] dentro de uma pasta components. Para isso, ele
pode criar os arquivos manualmente ou com os seguintes comandos no
terminal:
mkdir src/components
touch src/components/[Link]
touch src/components/[Link]
* Conteúdo Básico: Para [Link] e [Link], você pode instruir o
aluno a adicionar um código simples para que os componentes sejam
válidos, por exemplo:
// src/components/[Link]
import React from 'react';
const Home = () => <h1>Página Inicial</h1>;
export default Home;
// src/components/[Link]
import React from 'react';
const About = () => <h1>Sobre Nós</h1>;
export default About;
* Adicionar o código base: O código fornecido na atividade já está
estruturado, mas o aluno precisa garantir que ele funcione
adequadamente e que as dependências (como React Router e react-
window) estejam integradas.
* [Link] Inicial: O aluno deve copiar o primeiro bloco de código
fornecido (Aplicação base) para o arquivo src/[Link].
Executar a Aplicação
Após seguir os passos anteriores, o aluno deve iniciar o servidor de
desenvolvimento com o comando:
npm start
Isso abrirá a aplicação no navegador (geralmente em
[Link]
Aplicação Base ([Link] em src)
Abaixo está o código de uma aplicação que renderiza uma lista de
usuários e permite adicionar mais usuários. Vamos usá-lo como ponto
de partida:
import React, { useState } from 'react';
function App() {
const [users, setUsers] = useState(['Alice', 'Bob', 'Charlie']);
const [newUser, setNewUser] = useState('');
const addUser = () => {
setUsers([...users, newUser]);
[SIS] [U2] [C3]
8 / 15
setNewUser('');
};
return (
<div>
<h1>Lista de Usuários</h1>
<input
type="text"
value={newUser}
onChange={(e) => setNewUser([Link])}
placeholder="Adicionar usuário"
/>
<button onClick={addUser}>Adicionar</button>
<ul>
{[Link]((user, index) => (
<li key={index}>{user}</li>
))}
</ul>
</div>
);
}
export default App;
Problema de Performance
À medida que a lista cresce, a aplicação fica mais lenta, pois a
renderização de toda a lista acontece toda vez que um novo usuário é
adicionado, mesmo que apenas um item mude. Vamos aplicar três
técnicas para otimizar essa aplicação.
Passo 1: Memoization com [Link]()
Objetivo: Evitar renderizações desnecessárias dos itens da lista.
Problema: No código atual, toda vez que o estado da aplicação muda
(como ao adicionar um usuário), todos os itens da lista são
renderizados novamente, mesmo que não tenham mudado.
Solução: Usar [Link]() para memoizar cada item da lista, de
modo que ele só seja re-renderizado quando suas props (o nome do
usuário) mudarem.
Implementação:
Primeiro, extraia o item da lista para um componente separado e use o
[Link]().
Crie um novo arquivo src/components/[Link]:
// src/components/[Link]
import React from 'react';
const UserItem = [Link](({ user }) => {
[Link](`Renderizando UserItem: ${user}`); // Para observar a
otimização
[SIS] [U2] [C3]
9 / 15
return <li>{user}</li>;
});
export default UserItem;
Agora, modifique src/[Link]:
import React, { useState } from 'react';
import UserItem from './components/UserItem'; // Importe o UserItem
function App() {
const [users, setUsers] = useState(['Alice', 'Bob', 'Charlie']);
const [newUser, setNewUser] = useState('');
const addUser = () => {
setUsers([...users, newUser]);
setNewUser('');
};
return (
<div>
<h1>Lista de Usuários</h1>
<input
type="text"
value={newUser}
onChange={(e) => setNewUser([Link])}
placeholder="Adicionar usuário"
/>
<button onClick={addUser}>Adicionar</button>
<ul>
{[Link]((user, index) => (
<UserItem key={index} user={user} />
))}
</ul>
</div>
);
}
export default App;
Explicação:
* [Link]() faz com que o componente UserItem só seja re-
renderizado quando suas props mudam. Agora, ao adicionar um novo
usuário, apenas o item novo é renderizado, enquanto os outros
permanecem inalterados.
* Teste: Abra o console do navegador e observe as mensagens de
"Renderizando UserItem" ao adicionar novos usuários. Você verá que
apenas o novo item é logado após a primeira renderização.
[SIS] [U2] [C3]
10 / 15
Passo 2: Pure Components
Objetivo: Usar Pure Components para evitar renderizações
desnecessárias em componentes de classe.
Problema: Se tivermos algum componente de classe na aplicação,
como o formulário de adição de usuários, ele pode estar sendo re-
renderizado mesmo quando suas props e estado não mudam.
Solução: Transformar o componente de classe em um Pure Component
para que ele só se re-renderize se houver mudanças nas props ou no
estado.
Implementação: Neste exemplo, vamos transformar o botão de
adicionar em um Pure Component.
Crie um novo arquivo src/components/[Link]:
// src/components/[Link]
import React from 'react';
class AddUserButton extends [Link] {
render() {
[Link]("Renderizando AddUserButton"); // Para observar a
otimização
return <button onClick={[Link]}>Adicionar</button>;
}
}
export default AddUserButton;
Agora, modifique src/[Link]:
import React, { useState } from 'react';
import UserItem from './components/UserItem';
import AddUserButton from './components/AddUserButton'; // Importe o
AddUserButton
function App() {
const [users, setUsers] = useState(['Alice', 'Bob', 'Charlie']);
const [newUser, setNewUser] = useState('');
const addUser = () => {
setUsers([...users, newUser]);
setNewUser('');
};
return (
<div>
<h1>Lista de Usuários</h1>
<input
type="text"
value={newUser}
onChange={(e) => setNewUser([Link])}
placeholder="Adicionar usuário"
[SIS] [U2] [C3]
11 / 15
/>
<AddUserButton onClick={addUser} /> {/* Use o componente Pure
*/}
<ul>
{[Link]((user, index) => (
<UserItem key={index} user={user} />
))}
</ul>
</div>
);
}
export default App;
Explicação:
* [Link] verifica se as props ou o estado do
componente mudaram antes de re-renderizar. Isso impede que o botão
seja re-renderizado toda vez que a lista de usuários for atualizada, já
que sua onClick prop (que é uma função) permanece a mesma (a
menos que a função addUser seja recriada em cada renderização de
App, o que não acontece aqui).
* Teste: Observe o console. Você verá "Renderizando AddUserButton"
apenas na primeira renderização ou se a onClick prop realmente
mudar.
Passo 3: Virtualização de Listas com react-window
Objetivo: Melhorar a performance ao renderizar uma lista grande,
carregando apenas os itens visíveis na tela.
Problema: Com muitos usuários na lista, a renderização de todos os
itens ao mesmo tempo pode ser lenta e ineficiente.
Solução: Usar a biblioteca react-window para virtualizar a lista e
renderizar apenas os itens visíveis na tela.
Implementação: Instale a biblioteca react-window (já instruído nos
passos iniciais):
npm install react-window
Substitua a renderização da lista por um componente virtualizado em
src/[Link]:
import React, { useState, useCallback } from 'react'; // Adicionado
useCallback
import UserItem from './components/UserItem';
import AddUserButton from './components/AddUserButton';
import { FixedSizeList as List } from 'react-window'; // Importe
FixedSizeList
function App() {
const [users, setUsers] = useState(['Alice', 'Bob', 'Charlie']);
const [newUser, setNewUser] = useState('');
[SIS] [U2] [C3]
12 / 15
// Memoize a função addUser para evitar que ela seja recriada em
cada renderização
// Isso é importante para AddUserButton (PureComponent) e para
evitar renderizações desnecessárias
const addUser = useCallback(() => {
setUsers((prevUsers) => [...prevUsers, newUser]); // Usar callback
para garantir o estado mais recente
setNewUser('');
}, [newUser]); // Dependência: newUser
// Componente de linha para a lista virtualizada
// style é crucial para o posicionamento do item pela react-window
const Row = ({ index, style }) => (
<div style={style}>
<UserItem user={users[index]} />
</div>
);
return (
<div>
<h1>Lista de Usuários</h1>
<input
type="text"
value={newUser}
onChange={(e) => setNewUser([Link])}
placeholder="Adicionar usuário"
/>
<AddUserButton onClick={addUser} />
{/* Substitua <ul> por List da react-window */}
<List
height={300} // Altura visível da lista
itemCount={[Link]} // Número total de itens na lista
itemSize={50} // Altura de cada item em pixels
width={300} // Largura da lista
>
{Row} {/* Passa o componente Row para renderizar cada linha */}
</List>
</div>
);
}
export default App;
Explicação:
* react-window permite renderizar apenas os itens visíveis da lista,
economizando recursos. No exemplo, a lista renderiza apenas os itens
[SIS] [U2] [C3]
13 / 15
que cabem em uma altura de 300px, carregando mais à medida que o
usuário rola a tela.
* height, itemCount, itemSize e width são props essenciais para
configurar a lista virtualizada.
* O componente Row (ou como você preferir chamar a função que
renderiza cada item) recebe index e style como props da react-window.
O style é crucial e deve ser aplicado ao elemento raiz do seu item para
que a virtualização funcione corretamente.
* A inclusão de useCallback para a função addUser é uma boa prática
para otimização quando se trabalha com PureComponent ou
[Link](), pois garante que a função addUser não seja recriada
desnecessariamente a cada renderização do App, o que faria com que
AddUserButton (um Pure Component) sempre re-renderizasse.
Entrega e Registro
Não esqueça de entregar e registrar na plataforma:
* Aplicação React otimizada usando [Link](), Pure Components
e react-window.
* Relatório explicando as melhorias de performance observadas antes
e depois das otimizações.
Dicas para o Relatório:
Para o relatório, o aluno pode fazer os seguintes testes e observações:
* Antes das otimizações (com o [Link] inicial):
* Adicionar muitos usuários (50, 100, 200).
* Observar a fluidez da digitação e da adição.
* Usar as ferramentas de desenvolvedor do navegador (aba
"Performance") para gravar um perfil de renderização ao adicionar
novos usuários. Focar no tempo de renderização e no número de
renderizações de componentes.
* Observar o uso de memória (aba "Memory").
* Depois das otimizações (com o [Link] final):
* Repetir os testes de adição de muitos usuários.
* Observar a melhoria na fluidez.
* Gravar novamente um perfil de performance e comparar com o
anterior. Deve-se notar uma redução significativa no tempo de
renderização e no número de componentes renderizados
(especialmente os UserItems).
* Observar o uso de memória.
O relatório deve descrever as observações, as ferramentas usadas para
medir a performance e como cada técnica (Memoization, Pure
Components, Virtualização) contribuiu para a melhoria.
Este roteiro, com as pequenas adições e ênfases, oferece um guia
completo e prático para o aluno entender e aplicar conceitos cruciais
de otimização em React.
[SIS] [U2] [C3]
14 / 15
[SIS] [U2] [C3]
15 / 15