Skip to content

Dex64ter/ignite-feed

Repository files navigation

Iniciando com React

O React é uma biblioteca de criação de interfaces altamente interativas. Geralmente isso significa tudo aquilo que o usuário interage quando utiliza sua aplicação podendo ser na web, mobile, TVs e até em VR.

Fundamentos do React

Iniciando os fundamentos do React, sabemos que anteriormente na Web 1, as páginas eram estáticas, não tinha a adequação por usuário, uma página com caracterísicas específicas para cada usuário, era sempre a mesma pra todo e qualquer pessoa que acessasse.

Conforme o tempo passou, foram criados diferente formas de criação de sites na web. Primeiramente citaremos aqui os Padrões de Renderização ou Rendering Patterns, entre eles os que vamos descrever a seguir.

SSR (Server Side Rendering)

Sempre que o usuário/browser faz uma requisição para o servidor, este possui código tanto front-end como back-end. O Back cria e faz a busca no banco de dados e devolve o html, css, js, pronto para o servidor carregá-lo. A tela fica branca enquanto carrega, geralmente é assim que podemos verificar, ela é presente em muitas aplicações da web hoje.

SPA (Simple Page Aplication)

A maioria das aplicações estão vindo com esse padrão de renderização. O browser ao acessar uma rota, o back-end busca no bando de dados, mas não ele não possui mais a compreensão de código html, css, js, ou seja, ele não possui mais a responsabilidade pela compreensão visual da tela/aplicação.

Na verdade ele vai apenas retornar os dados para o usuário, geralmente no formato JSON (JavaScript Object Notation), uma estrutura "universal" pois ele consegue ser interpretado por qualquer linguagem.

Nesse padrão em resumo ao invés de apenas uma aplicação com front e back-end para devolução de requisições, nós vamos ter duas ou mais aplicações divididas, uma com o back-end que retorna os dados em JSON e outra que obtém os dados em JSON e converter para HTML, CSS e JS.

Podemos ter múltiplos front-ends consumindo a mesma fonte de dados em JSON.

Bundlers & Compilers

  • Compilers

    • São ferramentas que convertem o nosso código para um formato que outra máquina possa entender. No caso do JavaScript é o babel que converte código em uma versão mais básica que seja fácil de ser compatível com qualquer browser.
  • Bandlers

    • Os bandlers entende e converte importações e exportações dentro da nossa aplicação em um único arquivo de bundle que é compatível com os browsers. No caso do JS, temos o Webpack, muito famoso na comunidade.

Dica: O site Can I Use mostra para nós o que os browsers atualmente suportam.

Em resumo, precisamos de compiladores pois nem todos os browsers e ambientes vão entender o código em sua última versão, e os bundlers por conta do suporte ou da falta de suporte dos browsers a entender importações entre arquivos JavaScript.

O Vite e o Snowball são alternativas para criação de projetos javaScript, pois eles utilizam EcmaScript modules nativos, então não é necessário bundling e ele próprio já faz o processo de compiling automático, então com eles não é necessário o uso de Webpack e Babel.

Criando um projeto React usando Vite

Criando um projeto com os seguintes comandos:

// yarn
yarn create vite

// npm
npm create vite@latest

O Vite iniciará o processo de criação do projeto com passos para o nome do projeto, template utilizado e qual linguagem utilizar. O usuário também pode configurar no momento do comando se assim desejar.

Para nossa aplicação optamos por utilizar React com tamplate em javascript para o passo a passo em torno dos fundamentos do React e da utilização do typescript.

Após criar o projeto, entramos na pasta dele e utilizamos o comando yarn ou npm i ou npm install assim teremos a seguinte organização dos arquivos:

Organização das pastas e arquivos

No terminal, já podemos utilizar o comando npm run dev ou yarn dev

O servidor abrirá uma porta onde deverá rodar o nosso projeto. Daqui em diante vamos entender um pouco mais sobre os arquivos principais em que se encontra o corpo projeto.

Página renderizada pelo projeto

Dentro da pasta /src temos vários arquivos. Excluimos todos os de estilização, os que terminam com .css, e retiramos suas importações dos arquivos App.jsx e main.jsx.

Dentro de App.jsx, no retorno a função, retiramos todo o html, com exceção da tag que contorna o todo. Dentro dela colocamos a tag <h1> com a mensagem "Hello World".

// App.jsx
function App() {
  return (
    <>
      <h1>Hello World</h1>
    </>
  )
}

export default App

No nosso arquivo main.jsx temos a nossa configuração do ambiente React.

import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
)

A importação React de 'react' é o coração da biblioteca react que utilizamos para que todos os componentes dela consigam ser utilizados e configurados de forma correta. É nossa importação que nos dá acesso as diferentes formas que o react assume, seja na web, mobile, tv ou VR.

A ReactDOM da 'react-dom/client' é a importação que nos dá acesso a árvore de elementos HTML ou a DOM (Documentation Object Model) trazendo a partir dela elementos criados no javascript como elementos html na aplicação.

O método createRoot() indica qual elemento html será utilizado para randerizar toda a árvore de elementos do React no HTML. Nesse caso será o elemento com id='root' e o elemento a ser randerizado será o <App /> que está dentro do componente <React.StrictMode>

O elemento no qual nosso arquivo main.jsx está referenciando se encontra dentro do arquivo index.html, que está na raiz do nosso projeto.

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <link rel="icon" type="image/svg+xml" href="/vite.svg" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Vite + React</title>
</head>
<body>
  <div id="root"></div>
  <script type="module" src="/src/main.jsx"></script>
</body>
</html>

Como podemos observar, é um html simples que a partir da tag <script> já utilizando o formato de importação e exportação que o 'vite' faz para nossa aplicação usando dentro da tag <script> type='module'. Logo após essa propriedade temos o arquivo no qual o html recebe os componentes a página, src="src/main.jsx" .

Componentes

O principal conceito que DEVE ser conhecido antes de se trabalhar com React é o conceito de componente.

Basicamente, o componente funciona como o desacoplamento de um pedaço de código da aplicação que pode ser reinserida várias vezes em outras partes do código com informações diferentes.

A extensão JSX tem relação direta com os componentes. JSX significa Javascript + XML, ou seja, é javascript aliado a uma linguagem de marcação como HTML.

Export default vs. named exports

Existem diferentes formas de importar e exportar funções, a primeira delas é a "named exports" nela você pode exportar qualquer função, qualquer componente e nomea-lo da forma que desejar sem que ocorra erro.

Já no "export default" a função não pode ser renomea-da em uma importação, ela deve ser usada com o nome da forma que foi criada. Geralmente o uso de cada um dos tipo depende, mas cada uma tem sua vantagem específica.

// Named Exports

// Post.jsx
function Post() {
  return <p>Post</p>
}

export default Post;

// App.jsx
import PostComponent from "./Post";

export function App() {
  return (
    <PostComponent />
  )
}
// Exports default

// Post.jsx
export function Post() {
  return <p>Post</p>
}

// App.jsx
import { Post } from "./Post";

export function App() {
  return (
    <Post />
  )
}

Propriedades

Como em muitas tags html, existem os atributos, <img/>, <a> entre outras tags possuem atributos como "src" e "href". Dentro dos componentes existem as nossas propriedades que podem ser criadas ou extendidas de outros componentes. Elas se assemelham muito aos atributos das tags html.

import { Post } from "./Post";

export function App() {
  return (
    <>
      <Post 
        author="Davi" 
        content="Lorem ipsum dolor sit amet consectetur adipisicing elit. A voluptas dicta nisi pariatur nulla iusto deleniti molestiae earum quibusdam quasi! Molestias veniam recusandae dolorem soluta quis. Ab at eaque dolorem."
      />

      <Post 
        author="Outro autor" 
        content="Lorem ipsum dolor sit amet consectetur adipisicing elit. A voluptas dicta "
      />
    </>
  )
}

A principal utilidade dessa propriedades é estabelecer diferentes tipos de conteúdo usando um mesmo componente com a mesma estilização e mesma funcionalidade.

Para recebermos essas propriedades nos componentes, utilizamos o termo "props" dentro das variáveis da função do componente. Em seguida usamos as propriedades herdadas nos locais do componente que criamos.

export function Post(props) {
  return (
    <div>
      <strong>{props.author}</strong>
      <p>{props.content}</p>
    </div>
  )
}

Dessa forma cada componente poderá ser formado por diferentes conteúdos.

Estrutura da aplicação

CSS Modules

Para fazermos nossa estilização no React, podemos simplesmente criarmos nosso arquivo CSS e importa-lo. Diferente de como era a importação dos estilos dentro da página HTML, no React nos podemos apenas importa-los como fazemos com os componentes.

import "./style.css";

export function App() {
  return (
    <>
      <Header/>
    </>
  )
}

Existe um deslize no React que pode acabar acontecendo algumas vezes com a estilização de seus componentes. Ao dedicar classes a alguns componentes, alguns nomes podem se chocar, para resolver essa questão, temos o Css Modules.

O Css modules já existe por padrão dentro da configuração do React e do Vite, para usá-lo basta criar um arquivo de estilização com a palavra 'module' como em 'style.module.css'.

Em resumo, após isso nós teremos a utilização de um css específico para determinado componente. Ao inspecionar o browser teremos o seguinte:

Imagem de como fica o nome do elemento na página

O Css module, troca o nome da classe para um que se diferencie de outros, caso tornamos a usar o mesmo nome de classe em outro elemento. Assim ele deixa cada estilização específica para cada componente.

Em relação a organização das pastas, criamos uma pasta chamada "components" onde ficará todos os nossos componentes, geralmente separados por pastas com o nome de cada componente. Dentro de cada pasta de componente, usamos o nome do componente para criar seu arquivo de estilização, como por exemplo, no caso do componente Header.jsx vamos ter o Header.module.css.

CSS Global

O CSS Global é uma forma de colocarmos uma estilização padrão para toda a nossa aplicação sem precisar coloca-la em todos os outros componentes.

Geralmente colocamos a importação do arquivo CSS na raiz da aplicação, no nosso caso, no arquivo App.jsx.

import "./global.css";

Algumas configurações padrões que a maioria coloca no arquivo global:

/* No :root podemos adicionar algumas variáveis que serão úteis */
:root {
  /*
  Sintaxe padrão para adição de variáveis:
  --nome-da-var: valor;

  ex:
  --white: #FFF;
  --link-img: "./caminho/imagem.png";
  */
}

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  /* 
  Aqui geralmente adicionamos a cor do background e
  a cor da fonte.
  */
}

body, input, textarea, button {
  /* 
  Aqui adicionamos a font-family, o tamanho da font e 
  o peso da fonte.
  */
}

Componente Header

Para implementação do componente Header, dentro da pasta de componentes ./src/components/ criamos os arquivos "Header.jsx" e "Header.module.css".

Ponto importante — Por padrão, os componentes devem ser criados com a primeira letra maiúscula, isso ajuda a diferenciar os elementos html dos componentes React, já que ambos existem no código.

Como o próprio nome diz, o componente Header será formado por uma tag <header>, razão essa que temos o nome do componente com letra maiúscula.

import styles from './Header.module.css'
import igniteLogo from '../assets/igniteLogo.svg'

export function Header() {
  return (
    <header className={styles.header}>
      <img src={igniteLogo} alt="Ignite Logo" />
      <strong>Ignite Feed</strong>
    </header>
  )
}

Os nomes das classes dos elementos dentro do componente estão dentro de chaves pois eles são representados pela variável styles que foi importada do css module do componente Header como já vimos.

O que há de novo até aqui é a forma de importação das imagens. Após baixarmos a imagem, colocamos ela dentro da pastas ./src/assets/ e de lá nós importamos usando o "export default" como já vimos antes.

Ao final da estilização temos o Header da seguinte forma:

Imagem do componente header na app

Componente: Sidebar

O Componente Sidebar é composto por uma tag <aside> e todos os elementos que ela compoe como <img>, <footer>, etc.

import styles from "./Sidebar.module.css";
import { PencilSimpleLine } from "@phosphor-icons/react";

export function Sidebar() {
  return (
    <aside className={styles.sidebar}>
      <img
        className={styles.cover}
        src=""
      />
      <div className={styles.profile}>
        <img className={styles.avatar} src="" />

        <strong>Davi Santos</strong>
        <span>Web Developer</span>
      </div>
      <footer>
        <a href="#">
          <PencilSimpleLine size={20} />
          Editar seu perfil
        </a>
      </footer>
    </aside>
  )
}

Algumas coisas novas que aprendemos nesse componente é que como as imagens serão dinâmicas de acordo com o usuário, elas não vão precisar de texto alternativo (<alt>). Outra coisa importante é o uso de Icons importados via libs que baixamos.

Utilizamos essas libs de ícones porque usar imagens baixadas sempre que precisarmos usar um ícone, acarretaria em um grande uso de links e baixaria uma quantidade de dados, o que deixaria a aplicação desnecessariamente pesada.

No nosso caso baixamos o Phosphor Icons através do npm i @phosphor-icons/react ou yarn add @phosphor-icons/react, para usarmos ele precisamos apenas importá-lo no componente que vamos usar e colocar o nome do ícone como componente na aplicação.

.sidebar {
  background: var(--gray-800);
  border-radius: 8px;
  overflow: hidden;
}

Algo interessante nesse trecho também, foi a explicação do overflow, que funciona como uma caixa. Basicamente ele expicita que tudo que estivar "overflow", ou seja, por fora da caixa, deve ser escondido.

Também temos o uso da função calc() do css:

.avatar {
  width: calc(3rem + 12px);
  height: calc(3rem + 12px);
  border-radius: 3px;
  border: 4px solid var(--gray-800);
  outline: 2px solid var(--green-500);
}

Componente: Post

Vamos começar esse componentes citando o processo de criação de componente. A organização é mto importante, mas não é bom criar diversas pastas logo no começo da criação da aplicação porque pode acabar deixando a aplicação mais pesada, mais complicada do que ela realmente é.

Por essa e outras razões, não há necessidade de uma pasta para cada componente nessa aplicação por agora.

Mais uma coisa que citamos aqui é quais os passos que devemos seguir. Em primeiro lugar, ao ver o design criado do componente, vamos pensar em qual estrutura html usar, pensando o que cada item é e como ele deve ser representado.

Em seguida, nós avaliamos a estilização da página e só então vamos para as funcionalidades.

Em ordem temos:

  • HTML e estruturação

  • CSS ou estilização

  • Funcionalidades

    A estrutura do post ficou a seguinte:

// Post.jsx
<article className={styles.post}>
    <header>
      <div className={styles.author}>
        <img className={styles.avatar} src="https://www.github.com/dex64ter.png" />
        <div className={styles.authorInfo}>
          <strong>Davi Santos</strong>
          <span>Dev Front-end</span>
        </div>
      </div>
      <time title='8 de novembro às 8:30' dateTime='2023-11-08 08:30:00'>Publicado há 1h</time>
    </header>
    <div className={styles.content}>
      <p>Fala galeraa 👋</p>
      <p>Acabei de subir mais um projeto no meu portifa. É um projeto que fiz no NLW Return, evento da Rocketseat. O nome do projeto é DoctorCare 🚀</p>
      <p>👉{" "} <a href="#">jane.design/doctorcare</a></p>
      <p>
        <a href="#">#novoprojeto</a>{" "}
        <a href="">#nlw</a>{" "}
        <a href="">#rocketseat</a>
      </p>
    </div>
  </article>

Algumas coisas que foram aprendidas nesse componente:

  • A tag <time> é útil para adesão de conteúdo de datas e hora.
  • No React, o html não adere ao uso de vários espaços, então o espaço no React é feito com {' '}
  • Usar .elemento + .elemento no css, permite que nós estilizemos apenas o .elemento que possui um .elemento anterior a ele
  • Usar .pai > .elemento no css, nos permite estilizar somente o .elemento que é filho direto de .pai

Formulário de comentários

Agora vamos começar a criar a estrutura e estilização do formulário de comentários, aprendendo também de algumas propriedades novas como o :focus do CSS

Em resumo, como já vimos antes, criamos uma parte dentro de Post para a parte de escrita de comentários de outros usuários. Para isso usamos uma tag de formulário.

// ...
// Post.jsx
<form className={styles.commentForm}>
  <strong>Deixe seu feedback</strong>
  <textarea
    placeholder="Comente algo..."
  />
  <footer>
    <button type="submit">Publicar</button>
  </footer>
</form>

Após feita a estrutura criamos a nossa estilização do formulário. Nessa parte, poemos destacar duas boas práticas interessantes.

.commentForm textarea:focus {
  color: var(--gray-300);
  outline: 1px solid var(--green-800);
  border: 1px solid var(--green-800);
}

.commentForm button[type=submit] {
  padding: 1rem 1.5rem;
  background: var(--green-500);
  color: var(--white);
  font-weight: bold;
  border-radius: 8px;
  border: 0;
  cursor: pointer;
  transition: background 0.1s;
}

No código CSS acima, temos a propriedade focus que altera quando um elemento da tela é clicado ou "focado" pelo usuário. No caso da nossa aplicação, ao focar no textarea do formulário dos comentários, o elemento irá ter uma borda e um outline de determinada cor verde, além da cor da fonte alterada.

Outro assunto interessante, na parte do css, é que o botão de submissão do formulário só deve aparecer ao se ter o formulário do comentário em foco.

Sendo assim, a visibilidade do elemento deve ficar escondida até o formulário estar em foco pelo usuário e podemos fazer isso com CSS.

.commentForm footer {
  visibility: hidden;
  max-height: 0;  
}

.commentForm:focus-within footer {
  visibility: visible;
  max-height: none;

}

Como os elementos filhos agregam a estilização do elemento pai, podemos deixar o elemento footer com visibility: hidden e max-height: 0 fazendo com que todos os filhos não apareçam junto do pai.

A propriedade ".commentForm:focus-within" especifica qual estilização o elemento a seguir deve ter quando o elemento .commentForm for focado pelo usuário. Dessa forma, o nosso footer e todos seus filhos terão sua visibilidade normal e sem altura máxima do elemento.

Component: Comment

Agora vamos começar a criar a estrutura do nosso componente de comentário, que exibirá cada comentário de um post do nosso feed.

// Comment.jsx
<div className={styles.comment}>
  <img src="https://github.com/lucasmatosc.png">
  <div className={styles.commentBox}>
    <div className={styles.commentContent}>
      <header>
        <div className={styles.authorAndTime}>
          <strong>Lucas Matos</strong>
          <time title='8 de novembro às 8:30' dateTime='2023-11-08 08:30:00'>Cerca de 1h</time>
        </div>
        <button title="Deletar comentário">
          <Trash size={24} />
        </button>
      </header>
      <p>Parabéns pelo projeto, ficou incrível!</p>
    </div>

    <footer>
      <button>
        <ThumbsUp size={20} />
        Aplaudir<span>20</span>
      </button>
    </footer>
  </div>
</div>

Relacionado ao uso de botões sem texto que são identificados apenas por ícones, é sempre bom colocarmos um título com a propriedade "title" por acessibilidade.

Dentro do Post utilizaremos esse componente dentro de uma div com className=commentList.

// ...
// Post.jsx
<div className={styles.commentList}>
  <Comment />
  <Comment />
  <Comment />
</div>

Componente: Avatar

Vamos lembrar que temos 2 grandes momentos em que é aconselhável criarmos um componente.

  1. Quando alguma coisa repete mais de 2 vezes em tela, geralmente com o mesmo visual e mesmo comportamento.

  2. Quando conseguimos tirar algo de um componente maior sem que aquele componente maior pare de funcionar.

A imagem de usuário presente tanto na sidebar como nós comentários e nos posts é um elemento que se repete várias vezes, possui um comportamento igual e com mesma estlização.

Criamos a nossa estrutura do componente Avatar.jsx:

export function Avatar({ hasBorder = true, src}) {
  return (
    <img className={hasBorder ? styles.avatarWithBorder : styles.avatar} src={src} />
  )
}

Ele é apenas uma tag img com dois tipos de estilos. Isso porque no componente Sidebar e Post a imagem de avatar possui borda estilizada enquanto que nos comentários não.

Utilizando a desestruturação de objetos, temos nossas propriedade "hasBorder" e "src" uma que indica se o Avatar terá borda estilizada ou não e outra com a fonte da imagem.

Substituindo a tag img dentro do componente Comment temos:

<Avatar hasBorder={false} src="https://fonteImagem.com/imagem.png" />

Aplicando Responsividade

Aqui é bem básico, vamos apenas alternar a visualização para diferentes dispositivos.

No momento temos a estilização e responsividade apenas para web. Para alternarmos para visualização em dispositivos menores ou móveis podemos fazer o seguinte:

/* App.module.css */
@media (max-width: 768px) {
  html {
    font-size: 87.5%;
  }

  .wrapper {
    grid-template-columns: 1fr;
  }
}

A @media é uma ferramenta CSS para adapatar as estilizações para uma característica específica do documento ( geralmente para o tamanho da tela ), dessa forma podemos alterar a estilização para ficar responsivo em diferentes telas.

Os motores do React

Iterando no JSX

A iteração no React é uma das ferramentas mais úteis para mostrarmos inúmeras informações em tela. Nessa parte dos ensinamentos, temos dois tipos de funções no js que iteram sobre arrays, .forEach() e o .map(). Entre essas duas funções apenas uma delas possui retorno, a função .map() e por conta disso ela é mais propriamente usada para mostrar componentes em tela.

No nosso exemplo em questão foi feito a iteração com os Posts da nossa aplicação:

// Exemplo de estrtura de Post
const posts = [
  {
    id: 1,
    author: {
      avatar: "https://www.github.com/MrPinabutter.png",
      name: "Vitinho",
      role: "Dev Front-end",
    },
    content: [
      { type: "paragraph", content: "Fala galeraa 👋", },
      { type: "paragraph", content: "Acabei de subir mais um projeto no meu portifa. É um projeto que fiz no NLW Return, evento da Rocketseat. O nome do projeto é DoctorCare 🚀", },
      { type: "link", content: "jane.design/doctorcare"},
      { type: "link", content: "#novoprojeto"}
    ],
    publishedAt: new Date("2023-12-23 08:30:00"),
    
  },
]
// Iteração sobre a list de posts com a função map
export function App() {
  return (
    <>
      <Header />
      <div className={styles.wrapper}>
        <Sidebar />
        <main>
          {posts.map(post => {          
            return (
              <Post
                key={post.id}
                author={post.author}
                content={post.content}
                publishedAt={post.publishedAt}               
              />
            )          
          })}
        </main>
      </div>
    </>
  )
}

Mesmo usando um exemplo criado dentro do próprio componente, podemos adicionar as informações recolhidas do exemplo dentro do componente <Post/> como suas propriedades.

Propriedades do Post

Nessa aula vamos aprender a como utilizar essa iteração para enviar os dados de cada post de nosso array para componente Post para que ele possa ser renderizado em tela dinamicamente.

Basicamente, receberemos os dados pelo argumento props no componente Post e em seguida usa-lo entre chaves em cada valor passado como argumento.

export function Post(props) {
  //...
  {props.author.avatar}
  {props.author.name}
  {props.author.role}
}

Uma ferramenta importante que podemos usar aqui para evitar o uso de variáveis muito longas é a desestruturação.

export function Post({ author, content, publishedAt }) {
  //...
  {author.avatar}
  {author.name}
  {author.role}
}

Usar a biblioteca date-fns é uma boa dica de formatação de datas e para utilizar o mesmo formato que utilizamos dentro de Post.jsx

Estado (useState)

Aqui vamos iniciar a construção de um formulário de comentários para aprendermos sobre o funcionamento da renderização do React, imutabilidade e como podemos utilizar hooks para controlar o valor de variáveis em um estado do React.

UseState é um hook do React muito útil para recuperar informações de variáveis e também modifica-las. Utilizando o conceito de imutabilidade, significa que você não pode alterar diretamente os valores com estado, usamos esse hook para guardar o valor de uma variável e modificá-la através de uma função própria do hook.

// Declaração de variável sem o hook
const comments = [
  "Post muito legal, meus parabéns!",
]

export function Post({ author, content, publishedAt }) {
  // ...
// Declaração de variável com o hook useState()

export function Post({ author, content, publishedAt }) {
  const [comments, setComments] = useState([
    "Post muito legal, meus parabéns!",
  ])
  // ...

No useState podemos tipificar a variável iniciando ela através do seu valor padrão, como no exemplo acima em que iniciamos a variável comments com o valor padrão de um array com um elemento dentro

Inserindo Comentários (Programação Declarativa)

Vamos aprender como utilizar do conceito de formulários e componentes controlados do ReactJS para podermos adicionar comentários com textos baseados no que digitamos no input de cada post.

Em relação ao formulário, quando o usuário submete as informações contidas nele através do click de um botão, toda a página recarrega pois ele tenta enviar uma requisição para uma página e como não temos um alvo, ele reinicia a nossa página.

No nosso componente utilizamos a função .preventDefault() para evitar o comportamento padrão do formulário ao ser submetido.

export function Post({ author, content, publishedAt }){
  // ...
  function handleCreateNewComment(event) {
    event.preventDefault()
  
    setComments([...comments, newCommentText])
    event.target.comment.value = ''
  }
  // ...
  return (
    // ...
    <form onSubmit={handleCreateNewComment}>
      // ...
    </form>
  )
}

Além disso, dentro das propriedades da tag form temos o onSubmit do React, ele executa uma função específica quando o formulário é submetido.

const [newCommentText, setNewCommentText] = useState('')

//  ...

function handleCreateNewComment(event) {
  event.preventDefault()

  setComments([...comments, newCommentText])
  setNewCommentText('')
}

//  ...

<form onSubmit={handleCreateNewComment} className={styles.commentForm}>
  <strong>Deixe seu feedback</strong>
  <textarea
    placeholder="Comente algo..."
    name='comment'
    value={newCommentText}
    onChange={handleNewCommentChange}
  />
  <footer>
    <button type="submit">Publicar</button>
  </footer>
</form>

Para recuperarmos um novo comentário, vamos monitorar toda vez que for modificado o valor da tag <textarea/> usando a função onChange que verifica a modificação e executa determinada ação assim que ocorre.

Daí a diferença de paradigmas que podemos verificar em React:

Programação imperativa: Quando falamos de programação imperativa, queremos que o programa execute passo-a-passo.

Programação Declarativa: Utilizamos com muito mais frequência no React. Nela, ao invés de falar uma sequência de regras a ser seguida a risca nós especificamos quais as condições para que uma ação aconteça, ou seja, para que uma ação ocorra, uma série de condições precisam ser consideradas.

Entendendo a Key

Existem 3 momentos no React em que um componente é renderizado novamente:

  1. Quando o estado altera;
  2. Quando a propriedade altera;
  3. Quando um componente pai renderiza novamente.

Nesses 3 momentos, o React carrega tudo da página, todos os arrays, componentes e componentes dentro de outros componentes.

Nesses casos, o uso da key= que é uma propriedade própria do React, comumemte usada principalmente em objetos listados, é imprescindível porque ela especifica quais elementos não serão necessários serem renderizados novamente na página.

Por exemplo:

  • Se os seguintes elementos com as keys 1, 2, 3 forem renderizados, quando um novo elemento for adicionado ( 4 ), o React compara todos os que já foram renderizados e os que não foram, dessa forma evitando renderizaç~eos desnecessárias.

Comunicação entre componentes

Uma das coisas mais importantes de se entender dentro do React, a comunicação entre os componentes da aplicação.

O exemplo que usamos para ajudar a entender isso é a parte de excluir comentário de dentro do post.

Nesse caso, utilizamos um botão proveniente de dentro do componente Comment para excluir um comentário da lista de comentários que está presente dentro do componente Post.

// Comment.jsx
export function Comment({ content, onDeleteComment }){

  function handleDeleteComment(){
    onDeleteComment(content)
  }
  // ...

  return (
    // ...

    <button onClick={handleDeleteComment} title="Deletar comentário">
      <Trash size={24} />
    </button>

    // ...  
  )
}
// Post.jsx
export function Post({ author, content, publishedAt }){
  
  function deleteComment(commentToDelete) {
    const CommentsWithoutOne = comments.filter(comment => {
      return comment !== commentToDelete;
    })

    setComments(CommentsWithoutOne);
  }
  
  return (
    // ...

    <div className={styles.commentList}>
      {
        comments.map(comment => {
          return (
          <Comment
            key={comment}
            content={comment}
            onDeleteComment={deleteComment}
          />)
        })
      }
    </div>
    // ...
  )
}

Como presente no exemplo, podemos utilizar as propriedades do componente para a comunicação entre eles.

O Post.jsx envia uma função como valor para a propriedade onDeleteComment do componente Comment e este recebe a função como parâmetro e envia o texto cujo comentário será excluído, então a função é executada no Post para fazer a retirada no comentário expecífico da lista.

Validação de formulário e Realização de likes

Para a validação do formulário, temos a propriedade required proveniente do html que permite exigir o conteúdo da tag para que o processo execute.

No componente Post possui um jeito melhor de validação onde podemos mudar a mensagem de validação, caso não tenha nada escrito no textarea usando a propriedade onInvalid={} passando a função necessária.

Para a realização dos likes dentro do componente Comment, usamos uma nova variável para guardar a quantidade. E com uma função onClick para capturas da ação do botão passamos uma nova função que acresce de 1 a variável de contagem dos likes.

function handleLikeComment(){
  setLikesComment(likesComment + 1)
}

Entendendo closures no React

Sempre que for atualizar uma informação e essa informação depende do valor que ela tinha anteriormente, ou seja, dela mesma, é sempre bom utilizar um padrão de funções.

function handleLikeComment(){
  setLikesComment((state) => {
    return state + 1
  })
}

Aprimorando a aplicação

Fundamentos do Typescript

  • O que é Typescript?

    • Ele foi adicionado como um conjunto fundamental em cima de JavaScript, para conseguirmos adicionar a tipagem estática em cima de uma linguagem com tipagem dinâmica
  • Por que utilizar Typescript?

    • Ele deixa o editor mais inteligente, todas as tipagens evitam uma série de erros dentro do código em produção.

Typescript se tornou uma ferramenta fundamental, a produtividade aumenta bastante além da diminuição da taxa de erros no código durante a produção.