Construindo seu primeiro componente em ReactJS
Olá amigos, hoje vamos construir um componente simples em ReactJS, mas passaremos por vários conceitos importantes.
Motivação
Componentes nos permite dividir nossa interface em partes independentes e reusáveis e isso nos ajuda a pensar cada parte de forma isolada.
Por exemplo, quando estamos construindo um site ou um sistema, os elementos tendem a se repetir para assim mantermos uma identidade visual coerente. Os botões tendem a ter as mesmas características de fonte, borda, raio da borda, cor de fundo, …
Como os elementos se repetem, podemos componentizar e depois usá-los quantas vezes quisermos. Outro benefício é que se um dia precisarmos mudar a cor de todos os botões de azul para vermelho, faremos isso em apenas 1 arquivo e não será preciso procurar no HTML todos os botões e ir trocando a cor.
Dessa forma tais princípios são atendidos:
-
Reusabilidade
- Escrevemos o código apenas uma vez e reusamos quantas vezes for necessário
-
Separação de conceitos (Separation of concerns)
- Um princípio que visa modularizar o código de forma que cada parte seja responsável por apenas uma função. Com isso, o código fica mais organizado e mais fácil de manter.
Vamos começar
Iniciaremos criando um React app usando o boilerplate fornecido pela equipe de desenvolimento do ReactJS: link.
Execute o seguinte comando no terminal:
npx create-react-app hello-react
Ele irá criar e um configurar um projeto inicial em React com tudo o que a gente precisa para começar. E não se engane, de iniciantes a seniors, quase todos desenvolvedores usam esse boilerplate.
Após criado o projeto, abra-o em seu editor preferido, no meu caso, vou usar o VS Code.
Seu Primeiro Componente
Digamos que queremos criar um componente que informe o nível de aprovação de um filme. O nosso componente tem uma aparencia similar a de uma barra de loading e pode apresentar valores de 0 a 100. O preenchimento da barra deve ser condizente com o nível de aprovação.
Estrutura de pastas
No editor de texto criaremos nosso componente em src/components/approval/aproval.jsx
. Algumas dessas pastas não existe e você deve criá-las. O ReactJS não te obriga a seguir uma estrutura de pasta, você pode organizar seu projeto do jeito que desejar, porém tendemos a seguir alguns padrões para um boa organização do código. Seu projeto deve ficar mais ou menos assim:
- public
- src
- App.css
- App.js
...
- components
- approval
- approval.jsx
Componente
Iremos utilizar a abordagem funcional para criação do componente, falo isso porque por muito tempo os componentes que guardavam estado no React precisa ser construido utilzando Classes, conforme o React tem avançado, cada vez mais utilizamos a abordagem funcional e uma tendencia que observamos é que componentes construído utilizando classes vão ser depreciados no futuro. No nosso arquivo approval.jsx, precisamos importar o React e criar uma função. Ele inicialmente deverá ficar assim:
// components/approval/approval.jsx
import React from 'react';
const Approval = props => {
}
export default Approval;
Essa a estrutura básica de um componente no React, você escreverá esse código diversas vezes, sugiro até criar um snippet no seu editor de texto para ganhar produtividade. A única alteração que você precisará executar será o nome da função. Agora iremos estilizar um pouco o nosso componente, para isso, utilizaremos o CSS dentro do arquivo JS (Sugiro a leitura da documentação)
Agora iniciaremos com uma estilização básica, utilizando o CSS dentro do ReactJS. Se você ainda não sabe como fazer isso, você pode ler a documentação ou ver esse post no Medium.
// components/approval/approval.jsx
import React from 'react';
const Approval = props => {
const approvalStyles = {
margin: '10px',
width: '200px',
height: '25px',
display: 'block',
border: '1px solid #ccc',
borderRadius: '7px',
}
const ratingStyles = {
width: '50px',
height: '25px',
borderRadius: '7px',
display: 'block',
backgroundColor: '#ccc',
}
return (
<div className='approval' style={approvalStyles}>
<div className='rating' style={ratingStyles}></div>
</div>
)
}
export default Approval;
Em HTML o que você vê no snippet acima seria o equivalente a:
<html>
<head>
<style>
div.approval {
margin: 10px;
width: 200px;
height: 25px;
display: block;
border: 1px solid #ccc;
border-radius: 7px;
}
div.rating {
width: 50px;
height: 25px;
border-radius: 7px;
display: block;
background-color: #ccc;
}
</style>
</head>
<body>
<div class='approval'>
<div class='rating'>
...
</div>
</div>
</body>
</html>
Continuando…
Todo componente no React deve retornar alguma coisa. Esse coisa chamamos de JSX e o React irá renderizar o elemento para gente. Dois pontos eu gostaria de destacar no código acima.
- Como class é uma palavra reservada no JS, precisamos chamar as classes do HTML de className.
- Os estilos dentro de um arquivo JS é um objeto e as chaves do objeto devem estar no padrão camelCase, assim, o seletor border-radius vira borderRadius, esse padrão se repete para qualquer seletor do CSS.
Agora iremos para o arquivo src/App.js, apagaremos quase tudo que tem lá e importaremos nosso primeiro componente. Ele deverá ficar assim:
// App.jsx
import Approval from './components/approval/approval'
function App() {
return (
<div className=""App"">
<Approval />
</div>
);
}
export default App;
E agora podemos iniciar o server para visualizar como ficou. Rode o seguinte comando no terminal e acesse localhost:3000
npm start
Você deverá ver isso:
Adicionando estado ao componente
Para adicionar estado ao componente, usaremos React Hooks, uma funcionalidade nova bastante poderosa e simples de usar.
Em tempos passados, os estados dos componentes eram administrados de forma diferente e só era possível criar componentes que guardavam estado utilizando classes.
Um componente sem estado e que irá ser renderizado de acordo com os parâmetros é denominado de componente puro (pure component) (Veja mais aqui). Em uma aplicação React temos uma predominância de componentes puros, pois assim se tornar mais fácil a manutenção do código, pois todo o estado da aplicação está centralizado em um (ou poucos) componentes.
O Estado no nosso componente irá representar o nível de aprovação. O nível zero será representado pela barra vazia e o nível cem será representado pela barra cheia. Para utlizar os Hooks precisamos primeiro importá-los no nosso componente.
// components/approval/approval.jsx
import React, { useState } from 'react';
Após importado, precisaremos criar uma nova variável e uma função para alterar seu valor. Para isso, utilizaremos o conceito de desestruturação do Javascript.
// components/approval/approval.jsx
const [approvalRating, setApprovalRating] = useState(45);
O useState retorna um array e utilizamos a desestruração para obter o primeiro e o segundo elemento desse array. O primeiro elemento é a variável e o segundo elemento a função responsável por atualizar o valor na variável e em seguida atualizar o componente na tela do usuário. O valor entre parenteses useState(45) é o valor inicial da variável.
Agora para que o componente seja preenchido conforme o valor da variável, precisaremos alterar um pouco o objeto ratingStyles
// components/approval/approval.jsx
const ratingStyles = {
width: `${(200 * approvalRating) / 100}px`,
height: '25px',
borderRadius: '7px',
display: 'block',
backgroundColor: '#ccc',
}
Feito isso, o componente será preenchido conforme o valor de approvalRating. Agora podemos ficar alterando o valor inicial de approvalRating e vermos o tamanho da barra sendo modificada.
Adicionando input para alteração do estado
Mas seria muito ruim ter que ficar mudando no código o valor do estado do componente. Para melhorar nosso componente, iremos adicionar um campo de texto para que o usuário possa alterar o valor da forma que ele desejar.
Adicionaremos um input e seu estilo. O componente deverá ficar assim:
// components/approval/approval.jsx
const Approval = (props) => {
const [approvalRating, setApprovalRating] = useState(10);
const approvalStyles = {
margin: "10px",
width: "200px",
height: "25px",
display: "block",
border: "1px solid #ccc",
borderRadius: "7px",
};
const ratingStyles = {
width: `${(200 * approvalRating) / 100}px`,
height: "25px",
borderRadius: "7px",
display: "block",
backgroundColor: "#ccc",
transition: ".2s",
};
const inputStyles = {
marginTop: "16px",
width: "100%",
height: "25px",
boxSizing: "border-box",
paddingLeft: "8px",
};
return (
<div className="approval" style={approvalStyles}>
<div className="rating" style={ratingStyles}></div>
<input type="number" max="100" style={inputStyles} />
</div>
);
}
Agora iremos fazer duas coisas:
- Adicionar o valor de approvalRating no campo
- Adicionar uma função de alteração do approvalRating
Assim, o input deverá ficar assim:
// components/approval/approval.jsx
<input
type="number"
max="100"
style={inputStyles}
value={approvalRating}
onChange={(e) => setApprovalRating(e.target.value)}
/>
E agora ao alterar o valor do input, o tamanho da barra do componente também irá mudar. Como sabemos que o valor não pode passar de 100, podemos incrementar ainda um pouco mais a função de alteração para fazer uma validação e não permitir valores maiores que 100.
A função e o componente deverão ficar assim:
// components/approval/approval.jsx
const onChangeApprovalHandler = (e) => {
if (e.target.value <= 100) {
setApprovalRating(e.target.value);
}
};
return (
<div className="approval" style={approvalStyles}>
<div className="rating" style={ratingStyles}></div>
<input
type="number"
max="100"
style={inputStyles}
value={approvalRating}
onChange={onChangeApprovalHandler}
/>
</div>
);
Para finalizar, perceba que a transição do comprimento da barra ao ser alterado o valor do campo é muito bruta. Iremos deixar a transição mais suave adicionando apenas uma linha de CSS no objeto ratingStyles
const ratingStyles = {
width: `${(200 * approvalRating) / 100}px`,
height: "25px",
borderRadius: "7px",
display: "block",
backgroundColor: "#ccc",
transition: ".3s",
};
Agora sim, temos uma transição mais fluida e elegante para o componente.
Código completo
- App.jsx
import logo from './logo.svg';
import './App.css';
import Approval from './components/approval/Approval';
function App() {
return (
<div className="App">
<Approval/>
</div>
);
}
export default App;
- Approval.jsx
import React, { useState } from "react";
const Approval = (props) => {
const [approvalRating, setApprovalRating] = useState(10);
const approvalStyles = {
margin: "10px",
width: "200px",
height: "25px",
display: "block",
border: "1px solid #ccc",
borderRadius: "7px",
};
const ratingStyles = {
width: `${(200 * approvalRating) / 100}px`,
height: "25px",
borderRadius: "7px",
display: "block",
backgroundColor: "#ccc",
transition: ".3s",
};
const inputStyles = {
marginTop: "16px",
width: "100%",
height: "25px",
boxSizing: "border-box",
paddingLeft: "8px",
};
const onChangeApprovalHandler = (e) => {
if (e.target.value <= 100) {
setApprovalRating(e.target.value);
}
};
return (
<div className="approval" style={approvalStyles}>
<div className="rating" style={ratingStyles}></div>
<input
type="number"
max="100"
style={inputStyles}
value={approvalRating}
onChange={onChangeApprovalHandler}
/>
</div>
);
};
export default Approval;
#Fim
Opa, tudo bem? Antes de você ir, te deixo aqui meu email: [email protected]
Teve alguma dúvida?
Você achou que eu escrevi alguma coisa errada? Erro de português?
Você tem uma forma melhor de resolver o problema?
Você tem alguma sugestão de tópico para eu escrever?
Ou se quiser conversar sobre qualquer outro assunto?
Vamos trocar uma ideia. Sinta-se livre para me enviar um email. Eu lhe responderei com o maior prazer!