Interface Gráfica - orivaldosantana/mvp_banco_talentos GitHub Wiki

Design

JSX

JSX (JavaScript XML) é uma extensão de sintaxe para JavaScript que é usada principalmente junto com React para descrever como a interface do usuário deve ser. É uma sintaxe semelhante ao HTML que permite escrever elementos HTML em JavaScript e inseri-los no DOM (Document Object Model) sem qualquer construção de createElement() ou appendChild(). DOM (Document Object Model) é uma interface de programação para documentos HTML e XML. Ele representa a estrutura do documento como uma árvore de objetos, onde cada objeto representa uma parte do documento (como um elemento HTML). Esses objetos podem ser manipulados e alterados, permitindo que os desenvolvedores alterem o conteúdo, a estrutura e o estilo dos documentos. JSX é usado para definir componentes. Cada componente React retorna um JSX que define como esse componente deve ser renderizado no DOM.

No contexto do React e JSX, quando um componente retorna JSX, o React transforma esse JSX em uma representação do DOM (chamada Virtual DOM). Quando o estado de um componente muda, o React atualiza essa representação do DOM e, em seguida, faz uma comparação (diffing) entre o DOM virtual atualizado e o DOM virtual anterior. Ele então atualiza o DOM real no navegador apenas com as partes que mudaram. Isso é muito mais eficiente do que re-renderizar todo o componente ou toda a página.

Exemplo de código:

export default function CollaboratorPage() {
  return (
    <div>
      <h1>Cadastro de Colaborador</h1>
      <FormCollaborator />
    </div>
  )
}

Aqui, CollaboratorPage é um componente React que retorna um JSX. O JSX é basicamente uma div que contém um h1 e outro componente FormCollaborator.

JSX é apenas uma representação visual do que o componente faz. Por trás dos panos, o React transforma esse JSX em chamadas React.createElement(). Portanto, o JSX é apenas uma maneira mais legível e conveniente de definir componentes React. Além disso, o JSX permite a inserção de expressões JavaScript dentro de chaves {}. Isso significa que você pode executar JavaScript dentro do JSX, permitindo uma renderização dinâmica de componentes.

Material UI

A biblioteca adota neste projeto para a construção de componentes do frontend é a Material UI, uma biblioteca popular de componentes de interface do usuário para React. Ela implementa o design do Material Design do Google, fornecendo uma variedade de componentes pré-construídos que seguem essas diretrizes de design. Os componentes do Material-UI incluem botões, cartões, diálogos, formulários, ícones, menus, barras de navegação, e muito mais. Cada componente é altamente personalizável e pode ser estilizado para se adequar à aparência e ao comportamento desejados.

Exemplo de uso de um componente para agrupar outros componentes e aplicar estilos a eles, Box:

      <Box
        sx={{
          display: 'flex',
          justifyContent: 'center',
          alignItems: 'center',
          flexDirection: 'column'
        }}
      >
        <Typography variant="h4" sx={{ color: '#3030a1', margin: 5 }}>
          {title}
        </Typography>
        ...
      </Box>

A propriedade sx é utilizada para aplicar estilos específicos diretamente ao componente.

Gravando Dados de Formulário

Esta seção apresenta uma sugestão, Server Actions, para enviar os dados de formulário para o servidor para serem armazenados em um banco de dados.

Server Actions

O conceito de ações de servidor (server actions) foi implementado na versão 14 do Next.js e facilita muito o envio de dados para o backend. Server Actions são funções assíncronas executadas do lado servidor, para mais informações clique aqui.

Exemplo a seguir mostra um código de uma página muito simples, apenas com uma caixa de texto e um botão. O código ficou salvo no arquivo app/server_action_test:

import {addTest} from "../lib/action"

const ServerActionTestPage = () => {
  return (
    <div>
      <form action={addTest}> 
      <input type="text" name="name" placeholder="Your name" />
      <button>Create</button>
      </form>
    </div>
  )
}

export default ServerActionTestPage

No Next.js 14 o atributo action do formulário HTML tem um papel de permitir acesso aos dados do formulário e enviá-los para a função associada a este atributo. No exemplo acima é a função addTest. O código abaixo, do arquivo app\lib\action.ts, implementa a função addTest:

export const addTest = async (formData: FormData) => {
  'use server'

  let name = fromData.get('name')
  console.log('addTest: ' + name)
}

Os dados do formulário chegam através do parâmetro formData. A função addTest apenas mostra o conteúdo que veio do formulário. A string 'use server' no início da função addTest indica que a execução de addTest será do lado servidor.

Retornando Mensagem

Quando a execução de uma função no estilo Server Action termina, é necessário retornar uma mensagem avisando ao usuário se a ação enviada via formulário concluiu com sucesso ou se ocorreu alguma falha. No código a seguir é retornado um objeto com o atributo message informando sobre o secesso ou falha na execução:

export async function createUser(formData: FormData) {

  ...

  try {
   
    ...

    return { message: 'User created!' }
  } catch (error) {
    ...
    return { message: 'Error creating user!' }
  } 

}

Considerando o código acima, como obter essa mensagem de erro no formulário? Uma alternativa é usar o Hook useActionState que permite atualizar estados com base no resultado de uma ação de formulário. Exemplo com base na página oficial do Next.js:

'use client'
 
import { useActionState } from 'react'
import { createUser } from '@/app/actions'
 
const initialState = {
  message: '',
}
 
export function Signup() {
  const [state, formAction] = useActionState(createUser, initialState)
 
  return (
    <form action={formAction}>
      <label htmlFor="email">Email</label>
      <input type="text" id="email" name="email" required />      
      <p>
        {state?.message}
      </p>
      <button>Sign up</button>
    </form>
  )
}

Para mais informações sobre o Hook useActionState, acesse a página oficial do React clicando aqui.

Alertas

As mensagens de sucesso ou de erro depois de uma ação no formulário devem ser exibidas para os usuários. Essa seção apresenta um exemplo de como usar o componente Alert do Material UI. As mensagens obtidas do retorno de uma ação de formulário são detectadas com um Hook que monitora as mudanças de uma varável estado atrelada ao formulário. Assim, o userEffect Hook muda o estado de uma variável associada ao componente Alert quando uma mensagem chega do formulário. O código será explicado em mais detalhes a seguir.

Exemplo de uso do hook useState do React:

  const [openAlert, setOpenAlert] = React.useState(true)

O useState permite adicionar estado local a componentes funcionais do React. O estado é uma maneira de preservar alguns valores entre as renderizações do componente. Ele está sendo usado para criar uma variável de estado chamada openAlert e uma função para atualizar essa variável, chamada setOpenAlert.

  • openAlert é a variável de estado atual. Seu valor inicial será o valor do argumento para useState (neste caso, true).

  • setOpenAlert é a função para atualizar openAlert. Quando a aplicação chama setOpenAlert com um novo valor, o React re-renderiza o componente com o novo valor de openAlert.

Então, sempre que for necessário alterar o valor de openAlert, é preciso chamar setOpenAlert com o novo valor.

Exemplo de uso do hook useEffect do React:

  useEffect(() => {
    if (state?.message) {
      setOpenAlert(true)
    }
  }, [state])

O useEffect é um hook que permite executar efeitos colaterais em componentes funcionais. Efeitos colaterais são basicamente qualquer coisa que interage com o mundo fora da função do componente - como manipulação de dados, assinaturas, timers, manipulação manual do DOM, etc.

Neste caso específico, o efeito está verificando se a propriedade message do objeto state existe e não é null ou undefined. Se message existir, ele chama a função setOpenAlert, com o argumento true, para abrir uma componente alerta na interface do usuário.

O vetor [state] no final do useEffect é a lista de dependências do efeito. Isso significa que o efeito será executado sempre que o valor de state mudar. Se state for o mesmo entre renderizações, o useEffect não será executado.

A sintaxe state?.message é chamada de encadeamento opcional. Se state for null ou undefined, state?.message será undefined, e a tentativa de acessar message não causará um erro.

Fetching

Apresentar os dados na interface gráfica é uma parte fundamental da aplicação, para tanto é recuperar dados em API ou até em banco de dados.

O exemplo a seguir mostra como recuperar dados de uma API em página web da aplicação:

...
import { getAllUser } from '../../lib/user/data'
import Page from '../../ui/page'
import SimpleTable from '../../ui/user/simpletable'

const ReportPage = async () => {
  const users = await getAllUser()
  ...

  return (
    <div>
      <Page title={'Relatórios'}>
        ...
        <SimpleTable rows={users} />
        ... 
      </Page>
    </div>
  )
}

export default ReportPage

A recuperação dos dados em um banco de dados pode ser ilustrada a seguir:

export const getAllUser = async () => {
  const prisma = new PrismaClient()

  try {
    const users = await prisma.user.findMany()
    return users
  } catch (error) {
    console.error(error)
  } finally {
    await prisma.$disconnect()
  }
}

O código acima pode ser implementado em um arquivo lib/user/data.js

Um exemplo de código recuperando dados de um API externa.

O exemplo a seguir é para quando os dados são obtidos de uma API: 
export const getAllUser = async () => {
  const response = await fetch(
    `${process.env.REACT_APP_API_URL}/users`,
     {  cache: 'no-store' } 
  )
  if (!response.ok) {
    throw new Error("Something went wrong")
  }
  //console.log(response.json())
  return response.json()
}

Mais informações acessar a documentação do Next.js.

Referências

⚠️ **GitHub.com Fallback** ⚠️