Skip to content
Learni
Voir tous les tutoriels
Développement Mobile

Comment développer une app mobile avec Expo en 2026

Read in English

Introduction

Expo est un framework open-source qui simplifie le développement d'applications mobiles React Native en gérant les configurations natives complexes. En 2026, avec l'SDK 52+, Expo excelle dans les performances natives, l'intégration IA et les builds cloud via EAS. Pourquoi l'utiliser ? Il réduit le temps de développement de 50% grâce à Expo Router pour la navigation file-based, les modules universels et le hot-reload instantané. Ce tutoriel intermédiaire vous guide pour créer une app todo-list avec authentification, API REST et persistance. Vous apprendrez à structurer un projet scalable, gérer l'état, appeler des APIs sécurisées et déployer sur App Store/Google Play. Idéal pour les devs React avec bases RN qui veulent passer pro. (128 mots)

Prérequis

  • Node.js 20+ et npm/yarn/pnpm
  • Connaissances en React et React Native
  • Compte Expo gratuit (expo.dev)
  • Expo Go app sur iOS/Android pour tests
  • Éditeur VS Code avec extension Expo Tools

Installation et création du projet

terminal
npm create expo-app TodoApp --template
cd TodoApp
npx expo install expo-router react-native-safe-area-context react-native-screens expo-linking expo-constants expo-status-bar
npx expo install @expo/vector-icons
npm install @tanstack/react-query
npx expo install expo-secure-store expo-auth-session

Cette commande crée un projet Expo avec template par défaut, installe Expo Router pour la navigation moderne et les dépendances essentielles comme React Query pour la gestion d'état async, SecureStore pour la persistance sécurisée et AuthSession pour l'auth OAuth. Évitez les templates vides pour gagner du temps sur la config initiale.

Configuration initiale d'Expo Router

Expo Router utilise une structure file-based : chaque fichier dans app/ devient un écran. Modifiez app.json pour activer les schemes et splash screen. Lancez npx expo start pour tester sur Expo Go. L'app basique affiche un écran d'accueil.

Layout racine avec navigation

app/_layout.tsx
import { Stack } from 'expo-router';
import { StatusBar } from 'expo-status-bar';

export default function RootLayout() {
  return (
    <>
      <StatusBar style="dark" />
      <Stack screenOptions={{ headerStyle: { backgroundColor: '#f4511e' } }}>
        <Stack.Screen name="index" options={{ title: 'Accueil' }} />
        <Stack.Screen name="login" options={{ title: 'Connexion' }} />
        <Stack.Screen name="todos" options={{ title: 'Mes Todos' }} />
      </Stack>
    </>
  );
}

Ce layout définit une pile de navigation Stack avec des options personnalisées comme la couleur d'en-tête. Il inclut StatusBar pour une intégration native. Piège : oubliez expo-status-bar et l'app crash sur Android ; toujours tester sur devices réels.

Écran de connexion avec AuthSession

app/login.tsx
import { useEffect } from 'react';
import { View, Text, Button, StyleSheet } from 'react-native';
import * as WebBrowser from 'expo-auth-session/providers/google';
import { makeRedirectUri } from 'expo-auth-session';
import { useRouter } from 'expo-router';

const discovery = { authorizationEndpoint: 'https://accounts.google.com/o/oauth2/v2/auth', tokenEndpoint: 'https://oauth2.googleapis.com/token' };

export default function Login() {
  const router = useRouter();
  const [request, response, promptAsync] = WebBrowser.useAuthRequest({ clientId: 'VOTRE_GOOGLE_CLIENT_ID', scopes: ['profile', 'email'], redirectUri: makeRedirectUri() }, discovery);

  useEffect(() => {
    if (response?.type === 'success') {
      const { authentication } = response;
      // TODO: Stocker token avec SecureStore
      router.push('/todos');
    }
  }, [response]);

  return (
    <View style={styles.container}>
      <Text>Connectez-vous avec Google</Text>
      <Button title="Se connecter" disabled={!request} onPress={() => promptAsync()} />
    </View>
  );
}

const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center' } });

Cet écran implémente l'auth Google via AuthSession, avec redirectUri dynamique. Remplacez 'VOTRE_GOOGLE_CLIENT_ID' par le vôtre (créé sur Google Cloud Console). Attention : configurez les URIs autorisés dans Google Console pour éviter les erreurs 403.

Gestion d'état et API avec React Query

React Query gère les queries/mutations pour les todos. Créez un provider dans _layout.tsx et un hook custom pour fetcher depuis une API JSONPlaceholder.

Provider QueryClient et écran Todos

app/todos.tsx
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { View, Text, FlatList, TextInput, Button, StyleSheet } from 'react-native';
import { useRouter } from 'expo-router';

type Todo = { id: number; title: string; completed: boolean };

export default function Todos() {
  const router = useRouter();
  const queryClient = useQueryClient();
  const [newTodo, setNewTodo] = React.useState('');

  const { data: todos = [], isLoading } = useQuery<Todo[]>({
    queryKey: ['todos'],
    queryFn: async () => {
      const res = await fetch('https://jsonplaceholder.typicode.com/todos?_limit=10');
      return res.json();
    },
  });

  const mutation = useMutation({
    mutationFn: (title: string) => fetch('https://jsonplaceholder.typicode.com/todos', {
      method: 'POST',
      body: JSON.stringify({ title, completed: false }),
      headers: { 'Content-Type': 'application/json' },
    }),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['todos'] });
      setNewTodo('');
    },
  });

  if (isLoading) return <Text>Chargement...</Text>;

  return (
    <View style={styles.container}>
      <TextInput style={styles.input} value={newTodo} onChangeText={setNewTodo} placeholder="Nouveau todo" />
      <Button title="Ajouter" onPress={() => mutation.mutate(newTodo)} />
      <FlatList
        data={todos}
        keyExtractor={(item) => item.id.toString()}
        renderItem={({ item }) => <Text style={styles.todo}>{item.title}</Text>}
      />
      <Button title="Déconnexion" onPress={() => router.push('/login')} />
    </View>
  );
}

const styles = StyleSheet.create({
  container: { flex: 1, padding: 20 },
  input: { borderWidth: 1, padding: 10, marginBottom: 10 },
  todo: { padding: 10, borderBottomWidth: 1 },
});

Cet écran fetch des todos via React Query, avec mutation pour ajouter. FlatList optimise le rendu. Intégrez le QueryClientProvider dans _layout.tsx (non montré pour brièveté). Piège : sans invalidateQueries, l'UI ne refresh pas après mutation.

Persistance sécurisée avec SecureStore

hooks/useAuth.ts
import * as SecureStore from 'expo-secure-store';
import { useEffect, useState } from 'react';

export function useAuth() {
  const [token, setToken] = useState<string | null>(null);

  useEffect(() => {
    SecureStore.getItemAsync('authToken').then(setToken);
  }, []);

  const login = async (newToken: string) => {
    await SecureStore.setItemAsync('authToken', newToken);
    setToken(newToken);
  };

  const logout = async () => {
    await SecureStore.deleteItemAsync('authToken');
    setToken(null);
  };

  return { token, login, logout };
}

Ce hook custom gère le token auth de manière sécurisée avec SecureStore (équivalent Keychain). Utilisez-le dans login.tsx pour stocker après auth. Sur Android, activez useAndroidKeyStore en config pour FIPS compliance.

Configuration EAS pour build et submit

terminal
npx eas login
npx eas build:configure
# Éditez eas.json
npx eas build --platform all --profile preview
npx eas submit --platform ios

EAS CLI gère les builds cloud sans Xcode/Android Studio. Créez eas.json avec profils (preview/production). Premier build génère credentials ; réutilisez-les. Évitez builds locaux pour scalabilité.

Bonnes pratiques

  • Utilisez TypeScript partout : évite 80% des bugs runtime avec types pour props et API.
  • Adoptez Expo Router : navigation déclarative, SEO-ready pour web.
  • Cachez avec React Query : stale-while-revalidate pour offline-first.
  • Sécurisez les tokens : toujours SecureStore, jamais AsyncStorage.
  • Testez sur devices : Expo Go pour dev, EAS pour prod.

Erreurs courantes à éviter

  • Oublier expo install : les libs natives crash sans prebuild.
  • Ignorer les schemes dans app.json : auth redirects échouent.
  • Pas de error boundaries : une query fail crash l'app entière.
  • Builds sans credentials : EAS bloque sur iOS provisioning.

Pour aller plus loin