Aula 25 – Golang – Fiber – React – Logout

Aula 25 – Golang – Fiber – React – Logout

Voltar para página principal do site

Todas as aulas desse curso

Aula 24                          Aula 26

Fiber

Fiber

Pacote Programador Fullstack

Pacote Programador Fullstack

Redes Sociais do Código Fluente:

facebook

 

 


Scarlett Finch

Scarlett Finch é uma influenciadora, 🎤 cantora e 🎶compositora pop britânica , 24 anos de idade, adora o Brasil e em especial o Rio de Janeiro.

Ela foi criada utilizando algumas ferramentas de IA como a que vou apresentar hoje, o Foooocus.

Siga a Scarlett Finch no Instagram:

 

 


Conecte-se comigo!

LinkedIn: Fique à vontade para me adicionar no LinkedIn.

Ao conectar-se comigo, você terá acesso a atualizações regulares sobre desenvolvimento web, insights profissionais e oportunidades de networking no setor de tecnologia.

GitHub: Siga-me no GitHub para ficar por dentro dos meus projetos mais recentes, colaborar em código aberto ou simplesmente explorar os repositórios que eu contribuo, o que pode ajudar você a aprender mais sobre programação e desenvolvimento de software.

Recursos e Afiliados

Explorando os recursos abaixo, você ajuda a apoiar nosso site.

Somos parceiros afiliados das seguintes plataformas:

  • letsrecast.ai – Redefina a maneira como você consome artigos com Recast. Esta plataforma transforma artigos longos em diálogos de áudio que são informativos, divertidos e fáceis de entender. Ideal para quem está sempre em movimento ou busca uma forma mais conveniente de se manter informado. Experimente Recast agora.
  • dupdub.com – Explore o universo do marketing digital com DupDub. Esta plataforma oferece ferramentas inovadoras e soluções personalizadas para elevar a sua estratégia de marketing online. Ideal para empresas que buscam aumentar sua visibilidade e eficiência em campanhas digitais. Descubra mais sobre DupDub.
  • DeepBrain AI Studios – Revolucione a criação de conteúdo com a tecnologia de inteligência artificial da DeepBrain AI Studios. Esta plataforma avançada permite que você crie vídeos interativos e apresentações utilizando avatares digitais gerados por IA, que podem simular conversas reais e interações humanas. Perfeito para educadores, criadores de conteúdo e empresas que querem inovar em suas comunicações digitais. Explore DeepBrain AI Studios.
  • Audyo.ai – Transforme a maneira como você interage com conteúdo auditivo com Audyo.ai. Esta plataforma inovadora utiliza inteligência artificial para criar experiências de áudio personalizadas, melhorando a acessibilidade e a compreensão de informações através de podcasts, transcrições automáticas e síntese de voz avançada. Ideal para profissionais de mídia, educadores e qualquer pessoa que deseje acessar informações auditivas de maneira mais eficiente e envolvente. Descubra Audyo.ai e suas possibilidades.
  • Acoust.io – Transforme sua produção de áudio com Acoust.io. Esta plataforma inovadora fornece uma suite completa de ferramentas para criação, edição e distribuição de áudio, ideal para artistas, produtores e empresas de mídia em busca de excelência e inovação sonora. Acoust.io simplifica o processo de levar suas ideias à realidade, oferecendo soluções de alta qualidade que elevam seus projetos de áudio. Experimente Acoust.io agora e descubra um novo patamar de possibilidades para seu conteúdo sonoro.
  • Hostinger – Hospedagem web acessível e confiável. Ideal para quem busca soluções de hospedagem de sites com excelente custo-benefício e suporte ao cliente robusto. Saiba mais sobre a Hostinger.
  • Digital Ocean – Infraestrutura de nuvem para desenvolvedores. Oferece uma plataforma de nuvem confiável e escalável projetada especificamente para desenvolvedores que precisam de servidores virtuais, armazenamento e networking. Explore a Digital Ocean.
  • One.com – Soluções simples e poderosas para o seu site. Uma escolha ideal para quem busca registrar domínios, hospedar sites ou criar presença online com facilidade e eficiência. Visite One.com.

Educação e Networking

Amplie suas habilidades e sua rede participando de cursos gratuitos e comunidades de desenvolvedores:

Canais do Youtube

Explore nossos canais no YouTube para uma variedade de conteúdos educativos e de entretenimento, cada um com um foco único para enriquecer sua experiência de aprendizado e lazer.

Toti

Toti: Meu canal pessoal, onde posto clips artesanais de músicas que curto tocar, dicas de teoria musical, entre outras coisas.

Lofi Music Zone Beats

Lofi Music Zone Beats: O melhor da música Lofi para estudo, trabalho e relaxamento, criando o ambiente perfeito para sua concentração.

Backing Track / Play-Along

Backing Track / Play-Along: Acompanhe faixas instrumentais para prática musical, ideal para músicos que desejam aprimorar suas habilidades.

Código Fluente

Código Fluente: Aulas gratuitas de programação, devops, IA, entre outras coisas.

Putz!

Putz!: Canal da banda Putz!, uma banda virtual, criada durante a pandemia com mais 3 amigos, Fábio, Tatá e Lula.

PIX para doações

PIX Nubank

PIX Nubank


Aula 25 – Golang – Fiber – React – Logout

Código da Aula

Centralizando o Estado do Usuário no React para Melhoria da Gestão e Acessibilidade dos Dados

Para colocar o botão de logout no nav, precisamos do user no componente nav.

Como vamos fazer isso?

Em aplicações React, manter o estado relacionado ao usuário em um local centralizado é uma prática recomendada, especialmente em aplicações onde múltiplos componentes precisam acessar ou modificar esses dados.

No nosso caso, tanto o componente de navegação (Nav) quanto a página inicial (Home) necessitam acessar as informações do usuário.

Ao fazer a chamada do Axios para recuperar os dados do usuário no componente App, que é o componente pai tanto de Nav quanto de Home, podemos facilmente passar esses dados como props para ambos os componentes.

Isso não só simplifica o fluxo de dados dentro da aplicação, como também facilita a manutenção, pois qualquer mudança relacionada à obtenção ou atualização dos dados do usuário pode ser gerenciada em um único local.

Além disso, isso nos permite implementar funcionalidades adicionais, como no caso desse projeto, um botão de logout no Nav, de maneira mais eficiente.

O estado do usuário, estando disponível no App, pode ser modificado diretamente de Nav sem a necessidade de múltiplos handlers ou contextos complexos.

Isso garante que o estado do usuário seja consistentemente atualizado e refletido em toda a aplicação, melhorando a experiência do usuário e a confiabilidade da interface.

Essa abordagem de centralização do estado também prepara o terreno para uma eventual expansão do aplicativo, onde componentes adicionais poderão necessitar acessar ou modificar as informações do usuário sem necessitar de uma reestruturação significativa do gerenciamento de estado.

Portanto, ajustar nossa arquitetura para recuperar e gerenciar o estado do usuário no componente App é uma decisão estratégica que melhora a eficiência do código e a escalabilidade da aplicação.

Visão da mudança na arquitetura

Visão da mudança na arquitetura

Vamos a prática!

Apague a parte em laranja do Home.tsx, porque estamos transferindo a chamada ao endpoint User, para o componente App.tsx, pai do Home.

src/pages/Home.tsx


import React, { useEffect } from 'react';
import axios from 'axios';
const Home: React.FC = () => {
  const [message, setMessage] = useState('');

  useEffect(() => {
    (async () => {
      try {
        const response = await axios.get('user');
        const user = response.data;
        setMessage(`Hi ${user.first_name} ${user.last_name}`);
      } catch (e) {
        setMessage('You are not logged in!');
      }
    })();
  }, []);

  return (
    <div className="container">
      <h1>{message}</h1>
    </div>
  );
}

export default Home;

A parte laranja no código abaixo, ou seja, a parte das mensagens, pertencem ao Home, por isso, vamos voltar com elas para o Home e deixar só a parte em azul.

src/App.tsx 


import React, { useState, useEffect } from "react";
import axios from "axios";
import "./App.css";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import Login from "./pages/Login";
import Home from "./pages/Home";
import Register from "./pages/Register";
import Nav from "./components/Nav";

function App() {

  useEffect(() => {
    (async () => {
      try {
        const response = await axios.get('user');
        const user = response.data;
        setMessage(`Hi ${user.first_name} ${user.last_name}`);
      } catch (e) {
        setMessage('You are not logged in!');
      }
    })();
  }, []);

  return (
    <div className="App">
      <Router>
        <Nav />
        <Routes>
          <Route path="/" element={<Home />} />
          <Route path="/login" element={<Login />} />
          <Route path="/register" element={<Register />} />
        </Routes>
      </Router>
    </div>
  );
}
export default App;

Então o App.tsx agora tá assim:

src/App.tsx 


import React, { useState, useEffect } from "react";
import axios from "axios";
import "./App.css";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import Login from "./pages/Login";
import Home from "./pages/Home";
import Register from "./pages/Register";
import Nav from "./components/Nav";

function App() {

  useEffect(() => {
    (async () => {
      try {
        const response = await axios.get('user');
        const user = response.data;
      } catch (e) {

      }
    })();
  }, []);

  return (
    <div className="App">
      <Router>
        <Nav />
        <Routes>
          <Route path="/" element={<Home />} />
          <Route path="/login" element={<Login />} />
          <Route path="/register" element={<Register />} />
        </Routes>
      </Router>
    </div>
  );
}
export default App;

Além de trazer de volta as mensagens ao Home, vamos precisar pegar esse User que será enviado ao Home pelo App.tsx.

Para isso vamos receber no Home a propriedade do User e também definir suas propriedades, enviado pelo App.

Remova também os imports do axios e o useEffect, porque não vamos usar ele mais nesse arquivo.

src/pages/Home.tsx


import React, { useEffect } from 'react';
import axios from 'axios';
type UserProps = {
    user: {
        first_name: string;
        last_name: string;
        email?: string;
    } | null;  // Indicates that user can be an object with user data or null
};

const Home: React.FC<UserProps> = ({ user }) => {
  let message;
  if(user){
    message = `Hi ${user.first_name} ${user.last_name}`;
  } else{
    message = 'You are not logged in!';
  }
  return (
    <div className="container">
      <h1>{message}</h1>
    </div>
  );
}

export default Home;

Com as modificações acima, o Home vai ficar assim:

src/pages/Home.tsx


import React from 'react';

type UserProps = {
    user: {
        first_name: string;
        last_name: string;
        email?: string;
    } | null;  // Indicates that user can be an object with user data or null
};

const Home: React.FC<UserProps> = ({ user }) => {
  let message;
  if(user){
    message = `Hi ${user.first_name} ${user.last_name}`;
  } else{
    message = 'You are not logged in!';
  }
  return (
    <div className="container">
      <h1>{message}</h1>
    </div>
  );
}

export default Home

Já que a chamada ao endpoint User está sendo no App.tsx, precisamos passar ele como uma propriedade para o componente Home.

src/App.tsx 


import React, { useState, useEffect } from "react";
import axios from "axios";
import "./App.css";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import Login from "./pages/Login";
import Home from "./pages/Home";
import Register from "./pages/Register";
import Nav from "./components/Nav";

function App() {
const [user, setUser] = useState(null); // Adding state to store user data
 useEffect(() => {
    (async () => {
      try {
        const response = await axios.get('user');
        const user = response.data;
        setUser(user);
      } catch (e) {
        setUser(null);
      }
    })();
  }, []);

  return (
    <div className="App">
      <Router>
        <Nav user={user}/>
        <Routes>
          <Route path="/"element={<Home user={user} />} /> // Passing the user to Home
          <Route path="/login" element={<Login />} />
          <Route path="/register" element={<Register />} />
        </Routes>
      </Router>
    </div>
  );
}
export default App;

E da mesma forma que fizemos para receber as propriedades do User enviado do App para o Home, faremos também do mesmo jeito, no Nav.

Vamos também transferir a parte em vermelho e trocar por {links}.

src/components/Nav.tsx 


import React, { useState } from 'react';
import axios from "axios";
import { Link } from "react-router-dom";
const Nav = ({ user }: { user: any }) => {
  const [isNavCollapsed, setIsNavCollapsed] = useState(true);
  const handleNavCollapse = () => setIsNavCollapsed(!isNavCollapsed);
  return (
    <nav className="navbar navbar-expand-lg navbar-dark bg-dark">
      <div className="container-fluid">
        <Link className="navbar-brand" to="/">Home</Link>
        <button className="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded={!isNavCollapsed} aria-label="Toggle navigation" onClick={handleNavCollapse}>
          <span className="navbar-toggler-icon"></span>
        </button>
        <div className={`${isNavCollapsed ? 'collapse' : ''} navbar-collapse`} id="navbarNav">
          <ul className="navbar-nav ms-auto">
            <li className="nav-item">
              <Link className="nav-link" to="/login">Login</Link>
            </li>
            <li className="nav-item">
              <Link className="nav-link" to="/register">Register</Link>
            </li>
          </ul>
        </div>
      </div>
    </nav>
  );
};

export default Nav;

Vamos modificar o html do Nav  e também verificar se o usuário está logado, se estiver, será mostrado no Nav o Logout, caso contrário, será mostrado Login e Register.

src/components/Nav.tsx 


import React, { useState } from 'react';
import axios from "axios";
import { Link } from "react-router-dom";
const Nav = ({ user }: { user: any }) => {
  
  const logout = async () => {
    await axios.post('logout', {});
  }
  let links;
  if(user){
    links = (
      <ul className="navbar-nav ms-auto">
        <li className="nav-item">
          <Link className="nav-link" to="/" onClick={logout}>Logout</Link>
        </li>
      </ul>
    )
  } else {
    links = (
      <ul className="navbar-nav ms-auto">
        <li className="nav-item">
          <Link className="nav-link" to="/login">Login</Link>
        </li>
        <li className="nav-item">
          <Link className="nav-link" to="/register">Register</Link>
        </li>
      </ul>
    )
  }
  const [isNavCollapsed, setIsNavCollapsed] = useState(true);
  const handleNavCollapse = () => setIsNavCollapsed(!isNavCollapsed);
  return (
    <nav className="navbar navbar-expand-lg navbar-dark bg-dark">
      <div className="container-fluid">
        <Link className="navbar-brand" to="/">Home</Link>
        <button className="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded={!isNavCollapsed} aria-label="Toggle navigation" onClick={handleNavCollapse}>
          <span className="navbar-toggler-icon"></span>
        </button>
        <div className={`${isNavCollapsed ? 'collapse' : ''} navbar-collapse`} id="navbarNav">
          <ul className="navbar-nav ms-auto">
            {links}
          </ul>
        </div>
      </div>
    </nav>
  );
};

export default Nav;

Testando

Veja que se você deslogar, ou logar caso esteja deslogado, a página não muda, a não ser que a gente recarregue a página dando um refresh.

Vamos mudar mais algumas coisas no App, Login e Nav para resolver isso.

src/App.tsx 


import React, { useState, useEffect } from "react";
import axios from "axios";
import "./App.css";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import Login from "./pages/Login";
import Home from "./pages/Home";
import Register from "./pages/Register";
import Nav from "./components/Nav";

function App() {
  const [user, setUser] = useState(null); // State to store user data
  const [login, setLogin] = useState(false);

  useEffect(() => {
    (async () => {
      try {
        const response = await axios.get("user");
        const user = response.data;
        setUser(user);// Update the state with user data
      } catch (e) {
        console.error("Error loading user data", e);
        setUser(null); // Sets the user to null in case of error
      }
    })();
  }, [login]);

  return (
    <div className="App">
      <Router>
        <Nav user={user} setLogin={ () => setLogin(false) }/>
        <Routes>
          <Route path="/" element={<Home user={user} />} />
          <Route path="/login" element={<Login setLogin={() => setLogin(true)} />} />
          <Route path="/register" element={<Register />} />
        </Routes>
      </Router>
    </div>
  );
}

export default App;

Estado login: A adição da variável login permite rastrear quando um login ou logout ocorre.

Essa variável é usada como uma dependência no useEffect, o que significa que cada vez que login é atualizado (login bem-sucedido ou logout), o useEffect é disparado novamente.

Objetivo: Recarregar as informações do usuário quando o status de login muda, sem precisar recarregar toda a página.

Isso melhora a experiência do usuário e torna a aplicação mais responsiva e eficiente.

A outra mudança foi do <Route path="/login" element={<Login />} /> para<Route path="/login" element={<Login setLogin={() => setLogin(true)} />} />.

Essa mudança consiste em adicionar uma propriedade ao componente Login.

Ao incluir setLogin={() => setLogin(true)}, você está passando uma função que atualiza o estado de login na aplicação quando o usuário efetua login com sucesso.

Isso permite que o componente Login interaja diretamente com o estado global de autenticação, atualizando-o conforme necessário sem precisar de recarregamento da página, facilitando o controle de acesso e a resposta imediata da interface ao estado de autenticação do usuário.

Agora no Login faça as mudanças indicada em azul no código abaixo.

src/pages/Login.tsx


import React, { useState, SyntheticEvent } from 'react';
import axios from 'axios';
import { Navigate } from 'react-router-dom';

const Login: React.FC<{ setLogin: (loggedIn: boolean) => void }> = ({ setLogin }) => {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [redirect, setRedirect] = useState(false);
  const submit = async (e: SyntheticEvent) => {
    e.preventDefault();

    // Using environment variable for API URL
    const apiURL = process.env.REACT_APP_API_URL || 'http://localhost:3000'; // Fallback to localhost if environment variable is not set

    try {
        // Fix axios.post call with URL and data as separate arguments
        const response = await axios.post(`${apiURL}/api/login`, {
          email, // Simplification, since the name of the property and variable are the same
          password,
        });

        // Check the response here (example: whether login was successful based on the response status)
        if (response.status === 200) {
          // If the response is successful, set the state to redirect
          setLogin(true);
          setRedirect(true);
        } else {
          // Here you can handle other status codes or set a state to display an error message
          console.error("Login falhou com status:", response.status);
          // Ideally I would set an error state here to inform the user that login failed
        }
      } catch (error) {
      console.error("Erro ao fazer login:", error);
      // Here you could also set an error state to inform the user about the problem
    }
  };

  if(redirect){
    return <Navigate to="/"/>;
  }
  return (
    <form className='form-floating' onSubmit={submit}>
      <h1 className="h3 mb-3 fw-normal">Please sign in</h1>
      <div className="form-signin">
        <input type="email" className="form-control" placeholder="name@example.com" required 
          onChange={e => setEmail(e.target.value)}
        />
      </div>
      <div className="form-signin">
        <input type="password" className="form-control" placeholder="Password" required 
          onChange={e => setPassword(e.target.value)}
        />
      </div>
      <button className="form-signin btn btn-primary w-100 py-2" type="submit">Sign in</button>
      <p className="mt-5 mb-3 text-body-secondary">&copy; 2017–2024</p>
    </form>
  );
}
export default Login;

A definição do componente Login:

const Login: React.FC<{ setLogin: (loggedIn: boolean) => void }> = ({ setLogin }) =>

Significa que Login é um componente funcional que espera uma propriedade chamada setLogin.

Essa propriedade é uma função que recebe um booleano indicando o estado de login e não retorna nada.

Essa função é usada para atualizar o estado de login no componente App após um login bem-sucedido, desencadeando mudanças no estado global e na UI.

Passagem de setLogin como prop para Login: setLogin é agora uma função que atualiza o estado login no App, que, quando chamado, desencadeia o useEffect para recarregar o usuário.

Objetivo: Atualizar o estado global login imediatamente após um login bem-sucedido, o que por sua vez atualiza o estado user no componente App e força a re-renderização do componente Nav.

src/components/Nav.tsx  


import React, { useState } from 'react';
import axios from "axios";
import { Link } from "react-router-dom";
const Nav = ({ user, setLogin }: { user: any, setLogin: (loggedIn: boolean) => void }) => {
  const logout = async () => {
    await axios.post('logout', {});
    setLogin(false);
  }
  let links;
  if(user){
    links = (
      <ul className="navbar-nav ms-auto">
        <li className="nav-item">
          <Link className="nav-link" to="/" onClick={logout}>Logout</Link>
        </li>
      </ul>
    )
  } else {
    links = (
      <ul className="navbar-nav ms-auto">
        <li className="nav-item">
          <Link className="nav-link" to="/login">Login</Link>
        </li>
        <li className="nav-item">
          <Link className="nav-link" to="/register">Register</Link>
        </li>
      </ul>
    )
  }
  const [isNavCollapsed, setIsNavCollapsed] = useState(true);
  const handleNavCollapse = () => setIsNavCollapsed(!isNavCollapsed);
  return (
    <nav className="navbar navbar-expand-lg navbar-dark bg-dark">
      <div className="container-fluid">
        <Link className="navbar-brand" to="/">Home</Link>
        <button className="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded={!isNavCollapsed} aria-label="Toggle navigation" onClick={handleNavCollapse}>
          <span className="navbar-toggler-icon"></span>
        </button>
        <div className={`${isNavCollapsed ? 'collapse' : ''} navbar-collapse`} id="navbarNav">
          <ul className="navbar-nav ms-auto">
            {links}
          </ul>
        </div>
      </div>
    </nav>
  );
};

export default Nav;

No componente Nav, as modificações incluem a adição de uma nova propriedade setLogin e o uso dessa função para atualizar o estado de login quando um usuário realiza o logout.

Adição da propriedade setLogin: setLogin: (loggedIn: boolean) => void: Esta parte do código define que setLogin é uma propriedade esperada pelo componente Nav, sendo uma função que recebe um booleano (loggedIn) e não retorna nada (void).

Essa função é passada para o Nav pelo componente pai (App), permitindo que Nav interaja diretamente com o estado de login global.

Teste novamente e veja se funcionou.

Na próxima vamos implementar o Esqueci a senha.

Código da aula: Github

Voltar para página principal do blog

Todas as aulas desse curso

Aula 24                          Aula 26

É isso!

A gente se vê na próxima.

Até lá!

\o/

Bons estudos. 😉

About The Author
-

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>