Pular para o conteúdo
⚛ QUICKSTART

React 18 + Vite SPA.

SPA sem SSR — session em localStorage, hook useAuth reutilizável e proteção de rotas via Context.

SPA vs SSR — entenda a diferença

Uma SPA (Single Page Application) com Vite roda inteiramente no browser. Não há servidor renderizando HTML — o bundle JS é baixado uma vez e tudo acontece no client.

Por isso a session do SuperDB Auth fica em localStorage (padrão), não em cookies httpOnly. Isso é adequado para a maioria dos casos; para SSR use o Quickstart Next.js.

Diferenças chave vs Next.js:

  • Sem middleware — proteção de rotas via React Context
  • Session em localStorage (persiste ao fechar e reabrir o browser)
  • Sem server components — tudo é client-side
  • Variáveis de ambiente com prefixo VITE_ (não NEXT_PUBLIC_)

Passo a passo

1Criar o projeto Vite

Use o template oficial do Vite para React com TypeScript. O scaffold já inclui hot-reload, aliases e configuração de build otimizado.

terminal
npm create vite@latest meu-app -- --template react-ts
cd meu-app
npm install

2Instalar o SDK

O mesmo pacote @superdb/auth-js funciona no Vite sem nenhuma configuração especial.

terminal
npm install @superdb/auth-js

3Variáveis de ambiente

No Vite, variáveis expostas ao browser precisam do prefixo VITE_. Crie o arquivo .env na raiz:

⚠️

Nunca coloque a Service Role Key no .env de uma SPA — ela seria exposta no bundle JS. A anon key é segura para o browser.

.env
VITE_SUPERDB_URL=https://auth.superdb.com.br
VITE_SUPERDB_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

4Criar o cliente

No Vite, use import.meta.env para acessar as variáveis de ambiente (não process.env).

src/lib/superdb.ts
import { createClient } from '@superdb/auth-js'

export const superdb = createClient(
  import.meta.env.VITE_SUPERDB_URL,
  import.meta.env.VITE_SUPERDB_ANON_KEY
)

5Hook useAuth

Crie um hook customizado que expõe o usuário atual e escuta mudanças de sessão em tempo real (login/logout em outra aba, etc.).

O onAuthStateChange dispara imediatamente com a sessão atual e depois a cada mudança — perfeito para inicializar o estado.

src/hooks/useAuth.ts
import { useState, useEffect } from 'react'
import { superdb } from '../lib/superdb'
import type { User } from '@superdb/auth-js'

export function useAuth() {
  const [user, setUser] = useState<User | null>(null)
  const [loading, setLoading] = useState(true)

  useEffect(() => {
    // Sessão inicial
    superdb.auth.getUser().then(({ data }) => {
      setUser(data.user)
      setLoading(false)
    })

    // Escuta mudanças de sessão (login/logout em qualquer aba)
    const { data: { subscription } } = superdb.auth.onAuthStateChange(
      (_event, session) => {
        setUser(session?.user ?? null)
        setLoading(false)
      }
    )

    return () => subscription.unsubscribe()
  }, [])

  async function signUp(email: string, password: string) {
    const { error } = await superdb.auth.signUp({ email, password })
    if (error) throw error
  }

  async function signIn(email: string, password: string) {
    const { error } = await superdb.auth.signInWithPassword({ email, password })
    if (error) throw error
  }

  async function signOut() {
    await superdb.auth.signOut()
  }

  return { user, loading, signUp, signIn, signOut }
}

6Context + proteção de rotas

Envolva o app com um AuthProvider e crie um componente ProtectedRoute para redirecionar usuários não autenticados.

src/contexts/AuthContext.tsx
import { createContext, useContext, ReactNode } from 'react'
import { useAuth } from '../hooks/useAuth'
import type { User } from '@superdb/auth-js'

interface AuthContextType {
  user: User | null
  loading: boolean
  signUp: (email: string, password: string) => Promise<void>
  signIn: (email: string, password: string) => Promise<void>
  signOut: () => Promise<void>
}

const AuthContext = createContext<AuthContextType | null>(null)

export function AuthProvider({ children }: { children: ReactNode }) {
  const auth = useAuth()
  return <AuthContext.Provider value={auth}>{children}</AuthContext.Provider>
}

export function useAuthContext() {
  const ctx = useContext(AuthContext)
  if (!ctx) throw new Error('useAuthContext deve estar dentro de AuthProvider')
  return ctx
}
src/components/ProtectedRoute.tsx
import { Navigate } from 'react-router-dom'
import { useAuthContext } from '../contexts/AuthContext'
import type { ReactNode } from 'react'

export function ProtectedRoute({ children }: { children: ReactNode }) {
  const { user, loading } = useAuthContext()
  if (loading) return <div>Carregando...</div>
  if (!user) return <Navigate to="/login" replace />
  return <>{children}</>
}

7Configurar rotas e rodar

Instale o React Router, configure as rotas e inicie o servidor de desenvolvimento.

terminal
npm install react-router-dom
npm run dev
src/App.tsx
import { BrowserRouter, Routes, Route } from 'react-router-dom'
import { AuthProvider } from './contexts/AuthContext'
import { ProtectedRoute } from './components/ProtectedRoute'
import LoginPage from './pages/Login'
import Dashboard from './pages/Dashboard'

export default function App() {
  return (
    <AuthProvider>
      <BrowserRouter>
        <Routes>
          <Route path="/login" element={<LoginPage />} />
          <Route path="/dashboard" element={
            <ProtectedRoute><Dashboard /></ProtectedRoute>
          } />
        </Routes>
      </BrowserRouter>
    </AuthProvider>
  )
}

Próximos passos

Essa página ajudou?