A beleza do React
Quando coisas complexas são abstraídas/encapsuladas, novas possibilidades surgirão.
Olá! Neste artigo, discutiremos por que o React é uma das bibliotecas mais populares entre os desenvolvedores front-end e iniciantes na programação. Além disso, apesar de este artigo ser sobre o React, também falarei sobre o navegador, tipos de sites e modelo de pensamento no desenvolvimento web. Falar sobre esses tópicos ajuda os iniciantes na programação web a se manterem atualizados com a tecnologia.
Informações essenciais que você precisa saber
Seja você um iniciante ou alguém com experiência prévia em React, é importante observar que é necessário ter um entendimento básico sobre programação web para compreender completamente alguns conceitos que podem não ser explicados explicitamente. No entanto, eu garanto que tudo o que discuto neste artigo pode ser compreendido e apreciado. Sendo assim, vamos percorrer uma lista de conhecimentos essenciais que serão resumidos em diversos pontos ao longo deste artigo.
- DOM - Modelo de Objeto de Documentos
- VDOM - DOM Virtual
- Gerenciamento de estado -> Veja meu artigo no medium sobre como gerenciar o estado de um aplicativo complexo
Vamos ver por que o React foi criado
Antes de adentrarmos na discussão sobre a abstração e sua relevância no React, é importante entender a motivação por trás da criação do React. Para compreender isso, vamos explorar como um navegador renderiza um site. O processo é relativamente simples: o navegador renderiza o HTML estilizado com CSS e modifica o comportamento da visualização (HTML e CSS) por meio do JavaScript. O React segue uma abordagem semelhante, mas introduz um nível de abstração que elimina a necessidade de nos preocuparmos com os mecanismos específicos utilizados para realizar as alteções na UI(Interface do usuário) utilizando o JavaScript. Agora, vamos aprofundar-nos mais sobre como uma aplicação web funciona sem o uso de framework/biblioteca para manipular a UI.
<body>
<input id="input" />
<button id="add-todo">Add</button>
<ul id="todos"></ul>
<script>
let todos = [];
const addBtn = document.querySelector("#add-todo");
const input = document.querySelector("#input");
const todosList = document.querySelector("#todos");
function addToDo() {
const description = input.value;
const task = {
id: Date.now(),
description,
};
todos.push(task);
input.value = "";
}
function onHandleClickAddTodo() {
if (input.value) {
addToDo();
renderTodos();
} else {
alert("Type something");
input.focus();
}
}
function renderTodos() {
todosList.innerHTML = "";
todos.forEach(
(todo) =>
(todosList.innerHTML += `<li data-id="${todo.id}">${todo.description}</li>`)
);
}
addBtn.addEventListener("click", onHandleClickAddTodo);
</script>
</body>
O aplicativo é uma lista de tarefas simples em que você pode adicionar tarefas digitando-as no input e clicando no botão "Adicionar". Se você examinar o código, você notará que um eventListener foi anexado ao botão. Além disso, sempre que uma nova tarefa é adicionada à lista, a lista existente precisa ser resetada e todos os elementos serão adicionados novamente.
Vamos ver juntos quais problemas podem surgir com esse aplicativo:
- Todas as etapas precisam ser definidas: Na verdade, esse argumento é meio engraçado, já que somos programadores e é isso que fazemos, escrevemos etapas que o computador deve executar conforme definido. Mas se você der uma olhada no código, toda vez que um novo item de tarefa é adicionado, é necessário escrever todo o fluxo para atualizar a lista de tarefas, desde a instrução no DOM até as manipulações de cada tarefa. Como você pode imaginar, em um aplicativo complexo, como a maioria das interfaces de usuário que temos hoje em dia, escrever tudo isso pode ser avassalador e não é o ideal, pois à medida que os aplicativos crescem, fica cada vez mais desafiador mantê-los.
- Vazamentos de memória(Memory leaks): Tenha em mente que os eventListeners não são removidos automaticamente. Dê uma olhada no addEventListener que adicionamos ao addBtn, não removemos o eventListener porque é um aplicativo simples, mas pense em um aplicativo complexo que possui muitas funcionalidades/componentes que precisam de listener, e quando devemos remover esses ouvintes? Apenas para esclarecer, navegadores modernos podem talvez limpar esses EventListeners pelo Coletor de Lixo(garbage collector), mas ainda é uma boa prática removê-los. Para obter mais informações, pesquise sobre os tipos de vazamentos de memória no navegador JavaScript(Types of Memory Leaks In JavaScript browser) e referências fora do DOM(Out of DOM reference).
Para concluir, se você precisa gerenciar um aplicativo complexo que requer atualizações frequentes na interface do usuário, logo enfrentará problemas para manter todos esses estados sincronizados e escrever todas essas etapas para a atualização e manipulação da interface do usuário. Se você deseja saber mais sobre aplicações web, confira meu outro artigo no medium.
A importância da abstração
Antes de nos aprofundarmos nos detalhes do React, vamos entender por que a abstração é importante. Pense em carros, celulares, computadores e até mesmo em seu próprio corpo. Não é necessário compreender detalhadamente o funcionamento interno dessas coisas para utilizá-las de forma eficaz e alcançar nossos objetivos.
Você já se perguntou como uma simples ligação entre dois celulares funciona? Para ser honesto, eu não tenho ideia da complexidade envolvida, e quanto aos carros? Quando você pisa no acelerador do carro, ele simplesmente responde e desloca, você não precisa entender como uma motor funciona, mas ainda assim ele te ajuda a ir do ponto A ao ponto B. No entanto, você sempre precisa prestar atenção a alguns detalhes, como a gasolina, a água e o trânsito. No React é a mesma coisa, você não precisa se preocupar com como ele funciona (você nem precisa saber o que é DOM e VDOM), mas precisa ficar atento a alguns detalhes. Acredito que você entendeu o poder da abstração, ela modela nosso mundo. Se você pensar profundamente, essa é a beleza da natureza, a abstração.
O que torna o React tão popular
Vamos conferir o código do ToDo em React.
export default function App() {
const [todos, setTodos] = useState([]);
const [description, setDescription] = useState("");
const inputRef = useRef(null);
const onHandleChangeDescription = (e) => {
setDescription(e.target.value);
};
const addTodo = () => {
const task = {
id: Date.now(),
description
};
setTodos((e) => [...e, task]);
setDescription("");
};
const onHandleClickAddTodo = () => {
if (description) {
addTodo();
} else {
alert("Type something");
inputRef.current.focus();
}
};
return (
<>
<input
ref={inputRef}
value={description}
onChange={onHandleChangeDescription}
/>
<button onClick={onHandleClickAddTodo}>Add Todo</button>
<ul>
{todos.map((e) => (
<TodoItem key={e.key} todo={e} />
))}
</ul>
</>
);
}
const TodoItem = ({ todo }) => {
const { description } = todo;
return <li>{description}</li>;
};
Se compararmos o código em vanilla JavaScript com o código em React, fica evidente a diferença. O código em React é mais legível e focado principalmente na lógica de negócio, e menos na definição de como o DOM deve ser atualizado. Isso significa esqueça a seleção de querySelectors, adição de IDs ou classes, uma vez que não é necessário fazer referência a eles. No React, cada parte do seu aplicativo é encapsulada e isolada das outras partes como um componente. Você só precisa se preocupar em aprender a lidar com os estados e organizar os componentes.
Isso é o que torna o React tão popular, pois ele é declarativo em relação ao funcionamento do seu código. Qualquer pessoa com pouca experiência pode entender e começar a trabalhar com react em poucas semanas.
Aprofundando um pouco mais
Como mencionei anteriormente, seu trabalho é lidar com os estados e os componentes. Se você der uma olhada novamente no nosso código em React, verá dentro do HTML uma tag chamada TodoItem, e é isso que torna o React tão especial. Você ficará surpreso, pois não é uma tag HTML e o TodoItem também não é uma tag HTML. O que você viu antes no retorno da função App ou TodoItem é o JSX, e o TodoItem em si é um Elemento do React. Falarei sobre essas coisas mais adiante.
Por enquanto, quero que você pense que o React revolucionou a o desenvolvimento Web por conta da sua facilidade. Como você pode ver, não é mais necessarios preocupar-se com as manipulções do DOM e podemos reutilizar, isolar em components. Sendo assim, construímos components que possuem seu próprio estado, singularidade e lógica de negócio, que podem ser reutilizados quantas vezes você quiser. E se precisar alterar algo em um desses componentes, basta alterá-lo em um único local e ele será substituído em todos os lugares.
Mais Abstração - JSX
Cada vez que nos aprofundamos no React, vemos sua beleza, e o JSX é mais um exemplo disso. Embora eu tenha mencionado antes, ainda não discutimos o JSX. Portanto, o JSX é uma extensão do JavaScript chamada XML, desenvolvida pelo Facebook para nos ajudar a descrever a interface do usuário de forma eficiente e legível. Deixe-me mostrar um código sem o uso do JSX:
React.createElement(type/component, props, children);
Como você pode ver, é apenas uma função que recebe alguns parâmetros. Até agora, nada estranho, mas imagine criar componentes dessa forma, que trabalho doloroso. Você pode pensar: "Ok, acho que entendi o ponto, mas o navegador entende JSX?" Vamos ver o que acontece nos bastidores.
return /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__.Fragment, {
children: [/*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxDEV)("input", {
ref: inputRef,
value: description,
onChange: onHandleChangeDescription
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 32,
columnNumber: 7
}, this), /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxDEV)("button", {
onClick: onHandleClickAddTodo,
children: "Add Todo"
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 37,
columnNumber: 7
}, this), /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxDEV)("ul", {
children: todos.map(e => /*#__PURE__*/(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxDEV)(TodoItem, {
todo: e
}, e.key, false, {
fileName: _jsxFileName,
lineNumber: 40,
columnNumber: 11
}, this))
}, void 0, false, {
fileName: _jsxFileName,
lineNumber: 38,
columnNumber: 7
}, this)]
}, void 0, true);
Estou mostrando a você o bundle gerado pela aplicação sem o JSX, uma vez que o navegador não o entende e precisa ser compilado. Agora acredito que você entendeu por que usamos o JSX.
DOM e VDOM
Como você sabe, é responsabilidade do React lidar com instruções de baixo nível, como manipulação do DOM. A DOM virtual(VDOM) é um dos principais conceitos por trás do React. O VDOM no React é como uma cópia/representação do DOM, porém mais leve. O próprio DOM é apenas uma árvore dos elementos HTML.
Neste ponto, você pode pensar: o navegador já possui uma DOM, por que o React precisa de outra DOM? Quando falamos sobre alterações na interface do usuário, pode ser muito custoso realizar essas mudanças diretamente no DOM, pois todas as vezes que você modificar algo diretamente no DOM, a tela será redesenhada novamente. No VDOM, isso não acontece. A manipulação ocorre apenas no VDOM primeiro e, posteriormente, essas alterações são agrupadas e aplicadas em lotes(batch) no DOM. Dessa forma, a atualização é controlada e os custos das atualizações são minimizados. Lembre-se de que o VDOM é apenas um objeto JavaScript.
Redesenhar a página da web
Como eu disse antes, o problema com o DOM do navegador é o custo de atualizá-lo. Agora vou me aprofundar um pouco sobre o problema de desempenho causado pelo DOM do navegador. Se você é um desenvolvedor iniciante, talvez não conheça todos os comandos para manipular um elemento no documento. Ainda assim, aposto que você já usou uma dessas funções antes para manipular o elemento:
- document.getElementsByTagName;
- document.getElementById;
- document.querySelector.
A primeira e segunda função são ok para usar, já que a busca será feita com base em uma identificação(ID). No entanto, às vezes você deseja usar um seletor CSS, e nesse caso você escolhe a terceira função para isso. Mas pense em um aplicativo que tenha muitos nós, pode ser muito custoso, já que o document.querySelector vai procurar por todo o documento o elemento do início ao fim.
Agora, se você é novo no desenvolvimento web e começa a usar essas funções com frequência, a busca pelo elemento será mais lenta, pois um elemento pode estar muito profundo na árvore. Com as funções document.getElementsByTagName e document.getElementById, podemos otimizar a busca, mas muitas vezes não pensamos muito sobre o desempenho e acabamos tendo pensamentos do tipo "são apenas alguns milissegundos", mas no final isso faz diferença.
Se pensarmos na busca pelo elemento no DOM e em cada alteração a necessidade de redesenhar o layout, pequenos atrasos podem ocorrer e, em alguns sites antigos, você pode ver esse problema, é como se houvesse uma piscada nos botões e nas mensagens de alerta. Como você pode ter notado, o VDOM ajuda no desempenho do site, pois todas as alterações não são adicionadas uma de cada vez.
Quão pouco estamos cientes do desempenho do JavaScript?
Agora que estamos cientes de alguns problemas no DOM e que o VDOM é apenas um objeto JavaScript, você pode estar se perguntando como o VDOM do React nos ajuda a superar esses problemas no DOM. Honestamente, o React não faz nada mágico, é apenas uma questão de algoritmo e fluxo. Venha comigo e vamos ver o fluxo:
- Transaction: Sempre que atualizamos um componente e alteramos o teu estado, como adicionar um novo Todo em nossa lista, o React usará uma técnica chamada "transaction" para agrupar as atualizações, pense em adicionar e excluir um Todo ao "mesmo tempo". Essas duas ações serão colocadas em uma fila, dessa forma, ganhamos algum desempenho, pois não fazemos essa alteração de forma síncrona, há um debounce que faz com que o lote espere para ser aplicado, é como um agendamento, e não podemos controlá-lo.
- Reconciliation: Para tornar essas alterações mais eficientes em termos de desempenho, o React cria um novo VDOM e compara esse novo VDOM com o antigo VDOM, dessa forma, ele sabe quais mudanças foram feitas, e depois disso, essas alterações serão aplicadas ao DOM em de uma vez só. O processo de comparação é chamado de "reconciliation".
Conclusão
Até agora, neste artigo, falamos sobre coisas comuns no desenvolvimento web, verificamos algumas limitações ao manipular diretamente o DOM, forçando redesenhar a página toda vez que realizamos alguma alteração diretamente no DOM, e também vimos como o React supera essas limitações por meio do VDOM e o batch(aplicar todas as alterações de uma vez).
Neste ponto, acredito que você esteja ciente da beleza do React. Ele oferece tudo o que você precisa para começar a construir sua primeira aplicação sem precisar se preocupar ou aprender a manipular o DOM, pois o React cuidara disso. Sendo assim, você pode se concentrar apenas no que importa: seus componentes, a lógica de negócios, o estado da aplicação e assim por diante... É como um carro, você o compra para ir do ponto A ao ponto B sem se preocupar como o motor funciona, você apenas conhece o básico de como ele funciona e pode fazer praticamente tudo o que desejar.
Na parte final do artigo, também falei sobre o que está por trás do React, como a fila e como ele atualiza o estado. No próximo artigo, irei aprofundar ainda mais nesse assunto.
Vamos nos conectar
Sinta-se à vontade para entrar em contato comigo ou se conectar no LinkedIn :)