DEV Community

Cover image for Componentização: A Alma do React no Projeto Text Decoder Challenge
Vânia Gomes
Vânia Gomes

Posted on • Updated on

Componentização: A Alma do React no Projeto Text Decoder Challenge

Introdução

A componentização é um dos pilares fundamentais do React. Ela permite dividir a interface em partes menores, independentes e reutilizáveis, facilitando a manutenção, a escalabilidade e a legibilidade do código. No projeto Text Decoder Challenge, utilizamos essa abordagem para organizar a interface de codificação e decodificação de textos de maneira eficiente.

O Que é Componentização?

Componentização é o processo de dividir a interface do usuário em componentes. Cada componente encapsula uma funcionalidade específica, tornando o código mais modular. No React, os componentes funcionam como funções JavaScript, que aceitam "props" (propriedades) e retornam elementos que descrevem o que deve ser renderizado na tela.

No Text Decoder Challenge, cada parte da interface – o input de texto, os botões de codificar e decodificar, e o campo de exibição dos resultados – é um componente separado. Isso torna o código mais fácil de gerenciar e possibilita a reutilização desses componentes em diferentes contextos.

Propriedades (Props) e Estado (State)

Os props são valores passados de um componente pai para um componente filho. Eles são imutáveis, ou seja, o componente filho não pode modificá-los diretamente. Essa passagem de dados é essencial quando queremos que um componente exiba ou utilize informações que vêm de outro componente. No Text Decoder Challenge, usamos props para passar o texto digitado pelo usuário ao componente de decodificação. Por exemplo:

<Input
  id="inputtextDecodificador"
  value={inputValue}
  onChange={handleInputChange}
  placeholder="Digite um texto que deseja decodificar"
/>
Enter fullscreen mode Exit fullscreen mode

Aqui, o valor da entrada de texto (inputValue) é passado como prop para o componente Input. O componente pai (no caso, Decoder) controla o estado do valor através do state e o distribui ao filho via props.

O state é um dado que o componente gerencia internamente e que pode ser alterado ao longo do tempo. No React, quando o state é atualizado usando a função setState, fornecida pelo hook useState, o componente é re-renderizado automaticamente para refletir as mudanças. No nosso projeto, o estado armazena o texto codificado ou decodificado, e toda vez que ele é alterado, o React atualiza a interface. O uso do state pode ser visto neste trecho:

const [inputValue, setInputValue] = useState('');
Enter fullscreen mode Exit fullscreen mode

Aqui, (inputValue) é o estado atual, e (setInputValue) é a função usada para alterar esse estado. Cada vez que o usuário digita algo no campo de texto, a função handleInputChange chama (setInputValue) para atualizar o valor.

const handleInputChange = (e) => {
  setInputValue(e.target.value);
};
Enter fullscreen mode Exit fullscreen mode

Isso garante que a interface reaja dinamicamente às ações do usuário.

Exemplo Prático: Desafio do Decodificador de Texto

O Text Decoder Challenge permite que o usuário insira um texto e escolha entre codificar ou decodificar a mensagem. O projeto também fornece a opção de copiar o texto que deseja realizar a criptografia ou descriptografia para a área em que será realizada a codificação ou decodificação. A seguir, a estrutura básica do projeto, com componentes para cada parte essencial da interface:

No projeto original, identificamos componentes como:

Header: Um componente que exibe o cabeçalho da aplicação.
Input: Um componente reutilizável para entrada de texto.
Button: Um componente genérico para botões, esta sessão engloba a lógica de codificação e decodificação.
Decoder: A seção em que é possível inserir o texto que será decodificado.

Aplicando a Componentização

Identificação de Componentes

A estrutura do projeto já foi organizada de forma a utilizar componentes. Aqui estão os principais componentes identificados:

Input: Campo de entrada de texto, que pode ser reutilizado em diferentes partes do projeto.

Button: Um componente reutilizável para criar diferentes botões (por exemplo, "Codificar", "Decodificar", "Copiar").

Decoder: Seção que contém a lógica de copiar o texto que deseja codificar e a interação do usuário.

Componentes Detalhados

Decoder.js - Este componente contém a estrutura da interface, onde o usuário interage com o decodificador.

import React, { useState } from "react";
import { Input } from "../Input/Input";
import { Button } from "../Button/Button";

import text_decoder from "../../assets/text-decoder.png";
import styles from "./Decoder.module.css";

export function Decoder() {
  const [inputValue, setInputValue] = useState('');
  const [copySuccess, setCopySuccess] = useState('');

  function handleCopyText() {
    let textToCopy = document.querySelector('#inputtextDecodificador').value;

    navigator.clipboard.writeText(textToCopy).then(() => {
        setCopySuccess('Texto copiado com sucesso!');
    }).catch(err => {
        console.error('Ops, ocorreu um erro ao copiar o texto!');
    });
  }

  const handleInputChange = (e) => {
    if (e.target.value !== inputValue) {
      setInputValue(e.target.value);
    }
  };

  return (
    <section className={styles.container__decoder}>
      <div className={styles.content__text__decoder}>
        <img src={text_decoder} alt="Decodificador de Texto" />
        <h1 className={styles.title__text_decoder}>Nenhuma mensagem encontrada</h1>

        <Input
          id="inputtextDecodificador"
          value={inputValue}
          onChange={handleInputChange}
          placeholder="Digite um texto que deseja decodificar"
          className={styles.input__text__decoder}
        />

        <Button
          id="inputcopytext"
          onClick={handleCopyText}
          label="Copiar"
          aria-label="Copiar o texto inserido"
          className={styles.copy__button}
        />

        {copySuccess && <p className={styles.copyMessage}>{copySuccess}</p>}
      </div>
    </section>
  );
}
Enter fullscreen mode Exit fullscreen mode

Input.js - Um componente genérico para campos de entrada de texto.

import React from "react";
import styles from "./Input.module.css";

export function Input({ id, value, onChange, placeholder }) {
  return (
    <input
      id={id}
      value={value}
      onChange={onChange}
      placeholder={placeholder}
      className={styles.container__text__input}
    />
  );
}
Enter fullscreen mode Exit fullscreen mode

Button.js - Um componente para os botões de interação.

import React from "react";

import styles from "./Button.module.css";

export function Button({ id, onClick, label, className }) {
  return (
    <>
      <button
        id={id}
        className={className === "encrypt__button" ? styles.encrypt__button : styles.decrypt__button}
        onClick={onClick}
      >
        {label}
      </button>
    </>
  );
}
Enter fullscreen mode Exit fullscreen mode

Componente App: Integração de Componentes e Uso de State e Props

O componente App é o ponto central onde todos os componentes são integrados e onde a lógica do projeto é gerenciada. Ele organiza o fluxo da aplicação, utilizando o state para armazenar o valor de entrada do texto e os eventos de codificação e decodificação. O uso de props permite que os dados sejam passados para os componentes filhos, como o Input e o Button.

import React, { useState } from "react";

import { Header } from "./components/Header/Header";
import { Input } from "./components/Input/Input";
import { Button } from "./components/Button/Button";
import { Decoder } from "./components/Decoder/Decoder";
import bi_exclamation from "./assets/bi_exclamation-circle-fill.png";

import styles from "./App.module.css";
import "./styles/global.css";

function App() {
  const [inputValue, setInputValue] = useState('');

  const handleInputChange = (e) => {
    setInputValue(e.target.value);
  };

  function handleEncrypt() {
    let textoDigitado = document.querySelector('#inputtext1').value;

    const encryptedText = textoDigitado.split('').map(char => 
        String.fromCharCode(char.charCodeAt(0) + 1)
    ).join('');

    document.querySelector('#inputtext1').value = encryptedText;
  }

  function handleDecrypt() {
    let textoDigitado = document.querySelector('#inputtext1').value;

    const decryptText = textoDigitado.split('').map(char => 
        String.fromCharCode(char.charCodeAt(0) - 1)
    ).join('');

    document.querySelector('#inputtext1').value = decryptText;
  }

  return (
    <div>
      <Header />

      <main className={styles.container_main}>
        <section className="container_text">
          <Input
            id="inputtext1"
            value={inputValue}
            onChange={handleInputChange}
             placeholder="Digite seu texto"
            className={styles.container__text__input}
          />

          <div className={styles.container__info__type__text}>
            <div className={styles.content__info__type__text}>
              <img
                src={bi_exclamation}
                alt="Aviso do tipo de texto a ser inserido no input"
              />
              <p className={styles.paragraph__info__type__text}>
                Apenas letras minúsculas e sem acento.
              </p>
            </div>
          </div>

          <div className={styles.btn}>
            <Button
              id="codificador"
              label="Criptografar"
              onClick={handleEncrypt}
              className={styles.encrypt__button}
            />
            <Button
              id="descriptografar"
              label="Descriptografar"
              onClick={handleDecrypt}
              className={styles.decrypt__button}
            />
          </div>
        </section>

        <Decoder />
      </main>
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Como o App Integra os Componentes?

State e Input: O state armazena o valor do texto digitado no campo de entrada, que pode ser atualizado dinamicamente conforme o usuário interage com o campo.

Props e Button: As funções de onClick do botão de codificação e decodificação são passadas como props para os componentes Button. Isso permite que o botão acione as funções diretamente no componente pai (App), mantendo a lógica centralizada.

Componente Decoder: Além dos botões e do campo de texto, o componente App também integra o Decoder, que lida com a cópia de texto, reforçando o conceito de componentização e reutilização de componentes.

Com isso, o componente App conecta todos os blocos do projeto, centralizando a lógica e distribuindo as responsabilidades para os componentes especializados. A utilização de props e state garante uma interação fluida entre os componentes e a interface de usuário.

Benefícios da Componentização no Projeto

Reutilização: Componentes como os botões de codificar e decodificar podem ser reutilizados em diferentes partes do projeto ou até em outros projetos.

Facilidade de manutenção: Alterar a lógica de um componente afeta apenas aquele bloco específico, sem impactar o resto do código.

Clareza e organização: A separação de responsabilidades em componentes menores torna o código mais legível e fácil de entender.

Conclusão

A componentização no Text Decoder Challenge transforma a interface, tornando-a mais modular e escalável, promovendo reutilização e clareza. Ao usar props e state de maneira estratégica, garantimos uma experiência de usuário dinâmica e fluida, mantendo o código organizado e eficiente. Essa abordagem é essencial para a construção de interfaces de alta qualidade no React.

Bibliografia

Documentação: https://pt-br.react.dev/blog/2023/03/16/introducing-react-dev
Rocketseat: https://blog.rocketseat.com.br/react-do-zero-componentizacao-propriedades-e-estado/

Top comments (0)