DEV Community

Cover image for Iniciando o projeto Insta Doguinhos (em ReactJS)
patdc
patdc

Posted on

Iniciando o projeto Insta Doguinhos (em ReactJS)

Esse é o segundo projeto em React que inicio, e estou seguindo passo a passo o curso completo de React da Origamid, onde venho estudando Javascript desde o ano passado.

O início do projeto aborda conceitos de diversas coisas novas para mim: componentes, get, post, fetch que eu já conhecia, useState() (que estou ainda com dificuldades de entender totalmente), dentre outras coisas. O intuito desse post é compartilhar com vocês os avanços de meus estudos em programação. Pode ser que eu tenha noções que não estejam muito claras ainda e ficarei feliz com os comentários de vocês. 🙂

Vamos dar início ao projeto.

Configuração e teste da API Dogs

A primeira coisa que fizemos foi testar a API dogs, então criamos uma pasta "api" e dentro delas criamos o componente Api.js, onde vamos colocar os outros componentes para poder postar as fotos do aplicativo e também recuperá-las na sequência.

Apenas um parênteses antes de continuar:

Estudando em outros tutoriais na internet, percebi uma diferença entre ese tutorial da Origamid com outros tutoriais de react, e os componentes eram escritos de maneiras diferentes. E nessas pesquisas, descobri que existem dois tipos de componentes em React: os componentes de classe e os componentes funcionais sem estado. Aquiv ai uma breve definição, que encontrei nesse link.

Componentes de classe
Componentes de classe são componentes que possuem um alto nível de poder dentro da aplicação, pois além gerenciar o próprio estado, herdam os chamados métodos de ciclo de vida do React, lidam com partes lógicas da aplicação e manipulam eventos através de métodos que podem ser invocados em qualquer lugar do componente ou em seus filhos.

Componentes funcionais sem estado
Os componentes funcionais sem estado, são representados por funções JavaScript e como o nome sugere, não se preocupam (e nem devem se preocupar) com o gerenciamento de estado do componente, mas apenas com a apresentação dos dados na aplicação.

Portanto, percebi que nesse tutorial usaremos então os componentes funcionais sem estado. (assim que souber explicar melhor o porquê, venho aqui editar esse post :) )

O código Api.js ficou da seguinte forma:

import React from 'react'
import PhotoGet from './endpoints/PhotoGet'
import PhotoPost from './endpoints/PhotoPost'
import TokenPost from './endpoints/TokenPost'
import UserPost from './endpoints/UserPost'

const Api = () => {
    return (
        <div>
            Minha Api
            <h2>USER POST</h2>
            <UserPost />

            <h2>TOKEN POST</h2>
            <TokenPost />

            <h2>PHOTO POST</h2>
            <PhotoPost />

            <h2>PHOTO GET</h2>
            <PhotoGet />
        </div>
    )
}

export default Api
Enter fullscreen mode Exit fullscreen mode

Então aos pouquinhos estou entendendo o conceito de componentes dentro do React, e como fazemos para importar cada um deles em nosso aplicativo. Entendi que dessa forma fica muito mais organizado e fácil de modificar partes menores do aplicativo.


Agora vou falar sobre cada um desses componentes e explicar o que é feito dentro de cada um deles.

USERPOST

O componente USERPOST servirá para criar um novo usuário na base de dados, e vai ter como elementos os seguintes itens:

  • username
  • email
  • password

Por isso, logo dentro de nossa constante UserPost(), começamos declarando as constantes dos elementos reativos dessa componente:

const [username, setUsername] = React.useState('')
const [email, setEmail] = React.useState('')
const [password, setPassword] = React.useState('')
Enter fullscreen mode Exit fullscreen mode

Dessa forma, quando puxarmos essas constantes dentro do input, mais abaixo, elas são reativas. Na parte return deste componente, temos o seguinte código:

<form onSubmit={handleSubmit}>
            <input
                type="text"
                placeholder="username"
                value={username}
                onChange={({ target }) => setUsername(target.value)}
            />
            <input
                type="email"
                placeholder="email"
                value={email}
                onChange={({ target }) => setEmail(target.value)}
            />
            <input
                type="password"
                placeholder="password"
                value={password}
                onChange={({ target }) => setPassword(target.value)}
            />

            <button>Enviar</button>
        </form>
Enter fullscreen mode Exit fullscreen mode

Cada input vai possuir um type, placeholder, value (com valor reativo dentro dele), e o método onChange, que chamará uma função de callback, puxando e atualizando o elemento target e o valor dele. Entendi que esse método onChange é algo que sempre vai puxar essa função de callback.

Quando enviarmos o formulário aprós o preenchimento, usaremos o método onSubmit e chamaremos a função handleSubmit, que será descrita logo abaixo:

function handleSubmit(event) {
        event.preventDefault();

        fetch('https://dogsapi.origamid.dev/json/api/user', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
            },
            body: JSON.stringify({
                username,
                email,
                password
            })
        }).then(response => {
            console.log(response);
            return response.json();
        }).then(json => {
            console.log(json)
            return json;
        })
    }
Enter fullscreen mode Exit fullscreen mode

Ainda estou digerindo tudo o que acontece nessa função, pois são várias coisas novas para mim que ainda não estão completamente assimiladas. A função toma como parâmetro um event, e utilizaremos o método preventDefault() para que a página não recarregue assim que clicarmos no botão "Enviar" (padrão do sistema).

O que vai acontecer em seguida?

utilizaremos um fetch API, buscando um link da API dogs da Origamid. Geralmente o fetch possui como método um GET. Aqui, isso ser mudado, e é por isso que passo um segundo parâmetro dentro dele, sendo eles:

  1. o link
  2. um objeto com as seguintes chaves:
    1. method: POST
    2. headers: {'Content-Type': 'application/json' (perceba que a chave aqui é utilizada com aspas, apenas por ela possuir um hífen. Por isso que as outras chaves não possuem aspas).
    3. body: precisamos transformar esse json em string, para podermos recuperar o username, email e password.

Como todo fetch é uma Promise, damos continuidade a ela utilizando o .then, primeiramente para puxar a resposta dessa promise e, em seguida, transformar a resposta em json para depois retornar o json.

TOKENPOST

Agora passaremos para o próximo componente: o TokenPost.js, que servirá para criar um token único por usuário, destinado à autenticação do mesmo dentro do aplicativo, para que ele possa realizar posts. Você precisa estar logado e autenticado para realizar posts.

Dentro desse componente, teremos 3 elementos reativos:

const [username, setUsername] = React.useState('')
    const [password, setPassword] = React.useState('')
    const [token, setToken] = React.useState('')
Enter fullscreen mode Exit fullscreen mode

Percebam que aqui só precisarei do username e password para gerar o token. Não vamos precisar do e-mail novamente.

Na parte return temos o seguinte código:

 <form onSubmit={handleSubmit}>
            <input
                type="text"
                placeholder="username"
                value={username}
                onChange={({ target }) => setUsername(target.value)}
            />
            <input
                type="password"
                placeholder="password"
                value={password}
                onChange={({ target }) => setPassword(target.value)}
            />

            <button>Enviar</button>
            <p style={{ wordBreak: 'break-all' }}>{token}</p>
        </form>
Enter fullscreen mode Exit fullscreen mode

Esse código vai puxar uma função (sobre a qual já vou falar sobre), e ela vai principalmente nos retornar um token único, algo que se assemelha com a seguinte string:

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczpcL1wvZG9nc2FwaS5vcmlnYW1pZC5kZXYiLCJpYXQiOjE2MDMxOTc3MTYsIm5iZiI6MTYwMzE5NzcxNiwiZXhwIjoxNjAzMjg0MTE2LCJkYXRhIjp7InVzZXIiOnsiaWQiOiIxMjI4In19fQ.O9olTim21nnR42TY0RGve-CBUo_GswCAnC3LMN7QYys
Enter fullscreen mode Exit fullscreen mode

Para fins de estudo, criamos esse

no final do formulário apenas para facilitar o copiar e colar do token para os próximos passos. Note que inserimos dentro desse

um style para dizer a esse token de ser quebrado, pois, por ser muito longo, acaba criando uma barra horizontal no scroll e dificultando a navegação (ele corta no meio da string). Não conhecia esse estilo CSS.

Vamos agora falar da função handleSubmit() dentro desse componente:

function handleSubmit(event) {
        event.preventDefault();

        fetch('https://dogsapi.origamid.dev/json/jwt-auth/v1/token', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
            },
            body: JSON.stringify({
                username,
                password
            })
        }).then(response => {
            console.log(response);
            return response.json();
        }).then(json => {
            console.log(json)
            setToken(json.token)
            return json;
        })
    }
Enter fullscreen mode Exit fullscreen mode

O que fizemos aqui?

Novamente ela possui um fetch, mas dessa vez com outro link da api: o link que vai nos gerar o token. Utilizamos novamente o método POST, com headers de Content-Type application/json, para podermos puxar no body o username e password do usuário.

Em seguida temos os .then, que já são esperados em uma promise, mas repare que no último then, puxamos o token via o json.token e colocamos ele dentro do elemento reativo setToken, par que ele seja modificado imediatamente e que possamos conseguir acessar a esse token dentro da constante token, que foi declarada mais acima.

PHOTOPOST

Ao longo desse post, vou percebendo que muitas coisas se repetem nesse componentes, e estou passando a entender melhor o que acontece.

Dentro do componente PhotoPost.js, o intuito é de poder postar uma foto do seu cachorrinho, atribuindo a ela:

nome

idade

peso

foto (em formato de arquivo)

const [token, setToken] = React.useState('');
const [nome, setNome] = React.useState('');
const [peso, setPeso] = React.useState('');
const [idade, setIdade] = React.useState('');
const [img, setImg] = React.useState('');
Enter fullscreen mode Exit fullscreen mode

Mais uma vez usamos os elementos reativos que serão modificados de forma dinâmica.

Dentro do return deste componente, temos o seguinte código:

<form onSubmit={handleSubmit}>
            <input
                type="text"
                placeholder="token"
                value={token}
                onChange={({ target }) => setToken(target.value)}
            />
            <input
                type="text"
                placeholder="nome"
                value={nome}
                onChange={({ target }) => setNome(target.value)}
            />
            <input
                type="text"
                placeholder="peso"
                value={peso}
                onChange={({ target }) => setPeso(target.value)}
            />
            <input
                type="text"
                placeholder="idade"
                value={idade}
                onChange={({ target }) => setIdade(target.value)}
            />
            <input
                type="file"
                onChange={({ target }) => setImg(target.files[0])}
            />
            <button>Enviar</button>
        </form>
Enter fullscreen mode Exit fullscreen mode

Uma coisa que não falei anteriormente mas gostaria de deixar registrado, é que estou gostando muito de trabalhar com JSX, que é uma sintaxe semelhante ao XML, na qual você consegue escrever e compreender de uma melhor forma como será montado o seu component na UI. Vejam esse post sobre o assunto.

Esse formulário segue a mesma lógica dos outros, com a diferença para o input de imagem, que não possui placeholder e nem value. Além disso, ele não toma como argumento o target.value, como os outros inputs, mas sim, o target.files[0].

Agora declaramos a função handleSubmit():

function handleSubmit(event) {
        event.preventDefault();

        const formData = new FormData();
        formData.append('img', img)
        formData.append('nome', nome)
        formData.append('peso', peso)
        formData.append('idade', idade)

        fetch('https://dogsapi.origamid.dev/json/api/photo', {
            method: 'POST',
            headers: {
                Authorization: 'Bearer ' + token,
            },
            body: formData,
        }).then(response => {
            console.log(response);
            return response.json();
        }).then(json => {
            console.log(json)
            return json;
        })
    }
Enter fullscreen mode Exit fullscreen mode

Quais são as diferenças dessa função para as anteriores? Observemos:

Primeiramente, declaramos uma constante chamada formData. Eu não conhecia, então encontrei a seguinte definição:

Um elemento HTML

— quando especifico, o objeto FormData será preenchido com as chaves/valores atuais do formulário usando a propriedade name de cada elemento para as chaves e seu valor enviado para os valores. Também condificará conteúdo de entrada do arquivo.

Você poderia adicionar uma chave/valor usando FormData.append. E é isso que é feito na sequência desse código. ele insere a key, e em seguida o elemento reativo (ou seja, sem as aspas, para buscar o valor da constante inserida pelo usuário (e modificada pelo useState)).

Em seguida, realizamos novamente um fetch, e desta vez o headers possuirá um conteúdo diferente, ou seja, um "Authorization: 'Bearer ' + token". Nunca tinha ouvido falar sobre Bearer Authentication, então fui na internet pesquisar o que era. encontrei isto.

Bearer authentication (also called token authentication) is an HTTP authentication scheme that involves security tokens called bearer tokens. The name “Bearer authentication” can be understood as “give access to the bearer of this token.” The bearer token is a cryptic string, usually generated by the server in response to a login request. The client must send this token in the Authorization header when making requests to protected resources.

O final dessa frase explicou bem para que serve o Authorization: Bearer.

Em seguida, temos todos os thens, como se é esperado de uma promise, retornando o nosso json.

PHOTOGET

Agora vamos para o último endpoint, o PHOTOGET.

Ele servirá para buscarmos uma foto a partir de um certo ID. Para isso, precisaremos declarar uma constante id, usanto o useState novamente.

const [id, setId] = React.useState('');
Enter fullscreen mode Exit fullscreen mode

O retorno desse componente será o seguinte:

<form onSubmit={handleSubmit}>
  <input type="text" value={id} onChange={(target) => setId(target.value)} />
  <button>Enviar</button>
</form >
Enter fullscreen mode Exit fullscreen mode

Nada de novo aqui, estamos seguindo os mesmos passos dos outros componentes endpoint.

Agora vamos à nossa função de handleSubmit()

function handleSubmit(event) {
        event.preventDefault();

        fetch(`https://dogsapi.origamid.dev/json/api/photo/${id}`)
            .then((response) => {
                console.log(response);
                return response.json();
            })
            .then((json) => {
                console.log(json);
                return json;
            });
    }
Enter fullscreen mode Exit fullscreen mode

Reparem no fetch aqui, como ele é feito dessa vez.

Como queremos buscar o id de uma foto específica de algo que foi postado anteriormente, utilizaremos uma string literal dentro do fetch para podermos acessar à id dentro da string na qual está o link para o fetch. Em seguida temos novamente os then, como esperado, para termos a resposta em formato json.


Esta foi a primeira parte do projeto Insta Doguinhos que estou realizando em React. Ficarei feliz com comentários e feedback de vocês! <3

Top comments (1)

Collapse
 
ideamotive profile image
Idea Motive

Idea Motive developer is a part of backend development which includes integration of third-party web services and assists the frontend developers to complete the entire application development process. It is very hard to hire top node developers for the startup. They can get you different kinds of employees as developers, digital designers, project managers. Are you in search of Hire top node developers to work on your project? Then you go ideamotive.com. Visit our website for more information.