Skip to content

RN Lezione 11: useEffect e chiamate API

  • Capire useEffect per operazioni all’avvio
  • Fare chiamate fetch a API pubbliche
  • Gestire loading, errore e dati
  • Mostrare dati da API in FlatList

1. useEffect — eseguire codice al momento giusto

Section titled “1. useEffect — eseguire codice al momento giusto”

useEffect esegue codice in momenti specifici del ciclo di vita del componente.

import { useEffect } from 'react';
// 1. All'avvio (UNA SOLA volta)
useEffect(() => {
console.log('Componente montato!');
}, []); // ← array vuoto = esegui 1 sola volta
// 2. Quando una variabile cambia
useEffect(() => {
console.log('Il valore di X è cambiato:', x);
}, [x]); // ← esegui ogni volta che x cambia
// 3. Cleanup (componente smontato)
useEffect(() => {
console.log('Avvio...');
return () => {
console.log('Pulizia...'); // ← all'uscita
};
}, []);
const [dati, setDati] = useState(null);
const [loading, setLoading] = useState(true);
const [errore, setErrore] = useState(null);
useEffect(() => {
const caricaDati = async () => {
try {
const response = await fetch('https://api.esempio.com/dati');
if (!response.ok) throw new Error('Errore HTTP');
const json = await response.json();
setDati(json);
} catch (err) {
setErrore(err.message);
} finally {
setLoading(false);
}
};
caricaDati();
}, []);

// GET — leggere dati (default)
const response = await fetch('https://api.esempio.com/posts');
const dati = await response.json();
// POST — creare dati
const response = await fetch('https://api.esempio.com/posts', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer token...' // se serve
},
body: JSON.stringify({
titolo: 'Nuovo post',
corpo: 'Contenuto del post...',
}),
});
const risultato = await response.json();
// Controllare errori HTTP
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}

import { View, Text, FlatList, ActivityIndicator, StyleSheet } from 'react-native';
import { useState, useEffect } from 'react';
export default function App() {
const [posts, setPosts] = useState([]);
const [loading, setLoading] = useState(true);
const [errore, setErrore] = useState(null);
useEffect(() => {
fetchPosts();
}, []);
const fetchPosts = async () => {
try {
const response = await fetch(
'https://jsonplaceholder.typicode.com/posts?_limit=10'
);
if (!response.ok) throw new Error('Errore di rete');
const data = await response.json();
setPosts(data);
} catch (err) {
setErrore(err.message);
} finally {
setLoading(false);
}
};
// --- RENDER CONDIZIONALI ---
if (loading) {
return (
<View style={styles.center}>
<ActivityIndicator size="large" color="#3498db" />
<Text style={{ marginTop: 10, color: 'grey' }}>
Caricamento in corso...
</Text>
</View>
);
}
if (errore) {
return (
<View style={styles.center}>
<Text style={{ color: 'red', fontSize: 18, marginBottom: 10 }}>
❌ Errore
</Text>
<Text style={{ color: 'grey' }}>{errore}</Text>
</View>
);
}
return (
<View style={styles.container}>
<Text style={styles.titolo}>📰 Posts</Text>
<FlatList
data={posts}
renderItem={({ item }) => (
<View style={styles.card}>
<Text style={styles.id}>#{item.id}</Text>
<Text style={styles.postTitolo}>{item.title}</Text>
<Text style={styles.corpo}>{item.body}</Text>
</View>
)}
keyExtractor={item => item.id.toString()}
/>
</View>
);
}
const styles = StyleSheet.create({
center: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#f5f5f5',
},
container: {
flex: 1,
paddingTop: 50,
paddingHorizontal: 15,
backgroundColor: '#f5f5f5',
},
titolo: {
fontSize: 24,
fontWeight: 'bold',
marginBottom: 15,
},
card: {
backgroundColor: 'white',
padding: 15,
borderRadius: 12,
marginBottom: 10,
elevation: 1,
},
id: {
fontSize: 12,
color: '#3498db',
fontWeight: 'bold',
marginBottom: 5,
},
postTitolo: {
fontSize: 16,
fontWeight: 'bold',
marginBottom: 5,
textTransform: 'capitalize',
},
corpo: {
fontSize: 14,
color: 'grey',
lineHeight: 20,
},
});

4. ActivityIndicator — spinner di caricamento

Section titled “4. ActivityIndicator — spinner di caricamento”
import { ActivityIndicator } from 'react-native';
// Spinner grande blu
<ActivityIndicator size="large" color="#3498db" />
// Spinner piccolo
<ActivityIndicator size="small" color="grey" />
// Spinner con sfondo
<View style={{
position: 'absolute',
top: 0, left: 0, right: 0, bottom: 0,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'rgba(255,255,255,0.8)',
}}>
<ActivityIndicator size="large" />
</View>

5. API pubbliche gratuite per esercitazioni

Section titled “5. API pubbliche gratuite per esercitazioni”
APIURLCosa restituisce
JSONPlaceholderjsonplaceholder.typicode.com/postsPosts, users, comments
JSONPlaceholder usersjsonplaceholder.typicode.com/usersUtenti fittizi
Rick & Mortyrickandmortyapi.com/api/characterPersonaggi
Dog APIdog.ceo/api/breeds/image/randomImmagini cani
Open-Meteoapi.open-meteo.com/v1/forecastMeteo gratuito (no API key!)
useEffect(() => {
const caricaCane = async () => {
const res = await fetch('https://dog.ceo/api/breeds/image/random');
const data = await res.json();
setImmagine(data.message); // ← URL dell'immagine
};
caricaCane();
}, []);

6. Esempio guidato: Personaggi Rick & Morty

Section titled “6. Esempio guidato: Personaggi Rick & Morty”
import { View, Text, Image, FlatList, ActivityIndicator, StyleSheet } from 'react-native';
import { useState, useEffect } from 'react';
export default function App() {
const [personaggi, setPersonaggi] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchCharacter = async () => {
try {
const res = await fetch('https://rickandmortyapi.com/api/character');
const data = await res.json();
setPersonaggi(data.results.slice(0, 10));
} catch (err) {
console.error(err);
} finally {
setLoading(false);
}
};
fetchCharacter();
}, []);
if (loading) {
return (
<View style={styles.center}>
<ActivityIndicator size="large" color="#00b5cc" />
</View>
);
}
return (
<View style={styles.container}>
<Text style={styles.titolo}>👽 Rick & Morty</Text>
<FlatList
data={personaggi}
renderItem={({ item }) => (
<View style={styles.card}>
<Image source={{ uri: item.image }} style={styles.img} />
<View style={styles.info}>
<Text style={styles.nome}>{item.name}</Text>
<Text style={styles.specie}>{item.species}</Text>
<Text style={styles.stato}>
{item.status === 'Alive' ? '🟢' : '🔴'} {item.status}
</Text>
</View>
</View>
)}
keyExtractor={item => item.id.toString()}
/>
</View>
);
}

Hook/APICodiceDescrizione
useEffect baseuseEffect(() => {}, [])Esegue all’avvio
useEffect con dipuseEffect(() => {}, [x])Esegue quando x cambia
fetch GETawait fetch(url)Legge dati
fetch POSTawait fetch(url, {method:'POST', body:json})Invia dati
ActivityIndicator<ActivityIndicator size="large" />Spinner
JSON parseawait response.json()Converte risposta in oggetto

Crea un’app che:

  1. Carica utenti da https://jsonplaceholder.typicode.com/users
  2. Mostra in FlatList: nome, email, telefono
  3. ActivityIndicator durante il caricamento
  4. Gestione errore se la fetch fallisce
  5. Ogni utente ha un’avatar colorato con l’iniziale
{
"id": 1,
"name": "Leanne Graham",
"email": "Sincere@april.biz",
"phone": "1-770-736-8031 x56442"
}