Tu primera app con React Native
Una lista de tareas para iPhone y Android donde las personas se registran y solo ven sus propias tareas. Usa Expo y @espobase/client; la base de datos y las claves salen del panel.
1. Crea un proyecto y una tabla
En el panel, crea un proyecto. Abre Editor SQL y ejecuta:
create table todos ( id bigint generated by default as identity primary key, owner_id uuid not null default espobase.user_id(), title text not null, done boolean not null default false, created_at timestamptz not null default now() ); -- Row level security is already on. Each signed-in user sees and changes only their own todos: create policy "Users manage their own todos" on todos for all using (owner_id = espobase.user_id()) with check (owner_id = espobase.user_id());
2. Ajustes y claves
- API: crea una clave publicable y cópiala ahora; las claves solo se muestran al crearlas. Nunca pongas una clave secreta (
eb_sk_…) en una app: cualquiera puede abrir una app y leerla. - Autenticación › Ajustes: añade el enlace de tu app en URLs de redirección permitidas, por ejemplo
myapp://auth/callback, dondemyappes elschemede tu app.json. Los correos de confirmación y el inicio de sesión social vuelven a él.
3. Instala
npm install @espobase/client npx expo install @react-native-async-storage/async-storage react-native-get-random-values react-native-url-polyfill expo-web-browser expo-linking
React Native no tiene un par de cosas que sí tienen los navegadores. Dos paquetes pequeños las aportan; impórtalos antes que nada:
# .env (Expo reads EXPO_PUBLIC_ variables; the PUBLISHABLE key is safe in an app) EXPO_PUBLIC_ESPOBASE_URL=https://api.espobase.com/project/<your project ref> EXPO_PUBLIC_ESPOBASE_KEY=eb_pk_…
4. El cliente
Un teléfono no tiene localStorage, así que dale al cliente un lugar donde guardar la sesión. Se renueva sola y la persona sigue con la sesión iniciada al reiniciar la app.
// lib/espobase.ts
import "react-native-get-random-values"; // crypto.getRandomValues
import "react-native-url-polyfill/auto"; // a complete URL class
import AsyncStorage from "@react-native-async-storage/async-storage";
import { createClient } from "@espobase/client";
export const espobase = createClient(
process.env.EXPO_PUBLIC_ESPOBASE_URL!,
process.env.EXPO_PUBLIC_ESPOBASE_KEY!,
{ auth: { storage: AsyncStorage } },
);5. Registro e inicio de sesión
import * as Linking from "expo-linking";
import { espobase } from "@/lib/espobase";
// myapp://auth/callback (the scheme comes from app.json). Add it under Authentication › Settings.
const redirectTo = Linking.createURL("auth/callback");
await espobase.auth.signUp({ email, password, options: { redirectTo } });
await espobase.auth.signInWithPassword({ email, password });
// The confirmation email opens the app at redirectTo#type=signup&token=…
Linking.addEventListener("url", async ({ url }) => {
const token = new URLSearchParams(url.split("#")[1] ?? "").get("token");
if (token) await espobase.auth.verifyEmail({ token });
});
// Re-render when the user signs in or out.
espobase.auth.onAuthStateChange((_event, session) => setSession(session));Con la confirmación por correo activada, la persona recibe un enlace que abre tu app en la dirección que pasaste como redirectTo, con el token después de un #. Confírmalo con espobase.auth.verifyEmail({ token }).
7. Lee y escribe tus datos
import { useEffect, useState } from "react";
import { espobase } from "@/lib/espobase";
export function useTodos() {
const [todos, setTodos] = useState<{ id: number; title: string; done: boolean }[]>([]);
useEffect(() => {
espobase.from("todos").select("*").order("created_at").then(({ data }) => setTodos(data ?? []));
}, []);
return todos;
}
// owner_id fills itself in (its default is espobase.user_id()).
await espobase.from("todos").insert({ title: "Buy milk" });Cada solicitud lleva a la persona que inició sesión, y la base de datos aplica tu regla. Quien no ha iniciado sesión recibe una lista vacía, y nadie puede leer ni cambiar las tareas de otra persona, ni siquiera llamando a la API directamente.
8. Sube una foto
Crea un bucket en Storage y añade una política para que cada persona pueda escribir en su propia carpeta (mira la guía de subida de archivos). Pasa los bytes del archivo (un ArrayBuffer) a upload: Subida de archivos
import * as ImagePicker from "expo-image-picker";
import { espobase } from "@/lib/espobase";
const picked = await ImagePicker.launchImageLibraryAsync({ mediaTypes: ["images"] });
if (!picked.canceled) {
const asset = picked.assets[0]!;
const bytes = await (await fetch(asset.uri)).arrayBuffer();
const { data: session } = await espobase.auth.getSession();
const userId = session.session!.user.id;
await espobase.storage.from("photos").upload(`${userId}/photo.jpg`, bytes, { contentType: "image/jpeg" });
}Conviene saber
- Usa una build de desarrollo (
npx expo run:iosorun:android) en lugar de Expo Go para los enlaces de inicio de sesión: la dirección de Expo Go cambia con tu red, así que no se puede registrar una sola vez. - Otras configuraciones de React Native funcionan igual: instala los mismos paquetes, importa primero los dos polyfills y pasa un objeto de almacenamiento a
createClient. - El tiempo real también funciona: React Native incluye WebSockets, así que
espobase.realtimeno necesita nada más.
6. Inicia sesión con Google o GitHub
import * as WebBrowser from "expo-web-browser"; import * as Linking from "expo-linking"; import { espobase } from "@/lib/espobase"; export async function signInWithGoogle() { const redirectTo = Linking.createURL("auth/callback"); const { data } = await espobase.auth.signInWithOAuth({ provider: "google", options: { redirectTo, skipBrowserRedirect: true }, }); const result = await WebBrowser.openAuthSessionAsync(data!.url, redirectTo); if (result.type !== "success") return; // cancelled const code = new URL(result.url).searchParams.get("code"); if (code) await espobase.auth.exchangeCodeForSession(code); }Primero activa el proveedor en Autenticación › Proveedores. La app abre el proveedor en el navegador del sistema y recupera a la persona a través del enlace de tu app;
exchangeCodeForSessiontermina el inicio de sesión. Solo esta app puede terminarlo: el secreto de un solo uso se queda en el teléfono.