Lógica Compartilhada entre Web e Mobile
Os componentes EventList no web e EventListScreen no mobile têm algo em
comum: ambos fazem fetch para /api/events, armazenam o resultado em state,
tratam loading e erro. A lógica de UI é diferente (<article> vs <View>,
CSS vs StyleSheet), mas a lógica de dados é idêntica.
Podemos extrair essa lógica num custom hook. No projeto mobile, crie
src/useEvents.ts:
import { useState, useEffect } from "react";
import { Event } from "./types";
export function useEvents(baseUrl: string) {
const [events, setEvents] = useState<Event[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
fetch(`${baseUrl}/api/events`)
.then((res) => {
if (!res.ok) throw new Error(`Erro ${res.status}`);
return res.json();
})
.then((data) => setEvents(data))
.catch((err) => setError(err.message))
.finally(() => setLoading(false));
}, [baseUrl]);
return { events, loading, error };
}
Código 8-8: Hook que encapsula o fetch de eventos.
O EventListScreen fica mais enxuto:
import { useEvents } from "./useEvents";
import { API_BASE_URL } from "./config";
export default function EventListScreen() {
const { events, loading, error } = useEvents(API_BASE_URL);
if (loading) { /* ... */ }
if (error) { /* ... */ }
return (
<FlatList
data={events}
keyExtractor={(item) => String(item.id)}
renderItem={({ item }) => (/* ... */)}
/>
);
}
O mesmo hook funciona no projeto web — basta copiar useEvents.ts para
web/src/ e chamar useEvents("") (string vazia, porque no web o fetch usa
URLs relativas via proxy). A lógica de dados vive num lugar só; cada plataforma
cuida apenas da sua interface.
Esse é o nível de compartilhamento que faz sentido agora: um hook copiado entre
dois projetos. Quando o TamoJunto crescer e o número de hooks compartilhados
justificar a complexidade, podemos extrair um pacote shared/ no monorepo.