Custom Hooks, Error Boundaries & Architecture par Feature
Projet de synthèse — Semaine 4
1. Créer des custom hooks
Extraire la logique réutilisable
2. Implémenter les Error Boundaries
Gérer les crashs de composants
3. Organiser par feature
Architecture maintenable
4. Réviser semaines 3-4
Consolider les acquis
5. Appliquer les bonnes pratiques
Architecture React maintenable
Revue semaine 4
useEffect, useRef, React Router, Context, useReducer
Custom Hooks
Extraire la logique réutilisable
Error Boundaries
Gérer les crashs de composants
Architecture par Feature
Organisation et conventions de nommage
Mini-projet
Construire une app complète
Ce que nous avons appris
useEffect
Effets de bord
useRef
DOM & valeurs mutables
React Router
Navigation SPA
Context + useReducer
State global
useEffect(() => {
// Code exécuté après le rendu
// Ex: fetch, subscriptions, timers
return () => {
// Cleanup function
};
}, [dependencies]);
[]
1x au montage
[dep]
Ă€ chaque changement
pas de []
Ă€ chaque rendu
Accès DOM
const inputRef = useRef();
<input ref={inputRef} />
// Focus programmatique
inputRef.current.focus();
Valeur mutable
const countRef = useRef(0);
// Ne déclenche pas de re-render
countRef.current++;
đź’ˇ useRef = valeur persistante sans re-render
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/users/:id" element={<User />} />
</Routes>
</BrowserRouter>
useNavigate()
Navigation programmatique
useParams()
Accès aux paramètres d'URL
// 1. Créer le Context
const AppContext = createContext();
// 2. Provider avec useReducer
const [state, dispatch] = useReducer(reducer, initialState);
// 3. Consommer dans les composants
const { state, dispatch } = useContext(AppContext);
useReducer
State complexe avec actions
Context
Partager sans prop drilling
Extraire la logique réutilisable
Une fonction qui commence par use
et utilise d'autres hooks à l'intérieur
Un custom hook = une fonction qui :
Commence par use
Utilise d'autres hooks (useState, useEffect, etc.)
Retourne des valeurs ou fonctions
💡 Les autres hooks peuvent être utilisés uniquement à l'intérieur des custom hooks ou composants
Hook simple pour basculer un état booléen
function useToggle(initialValue = false) {
const [value, setValue] = useState(initialValue);
const toggle = () => setValue(v => !v);
return [value, toggle];
}
// Utilisation
const [isOpen, toggleOpen] = useToggle();
<button onClick={toggleOpen}>
{isOpen ? 'Fermer' : 'Ouvrir'}
</button>
Hook pour les appels API avec loading et error
function useFetch<T>(url: string) {
const [data, setData] = useState<T | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
fetch(url)
.then(res => res.json())
.then(setData)
.catch(() => setError('Erreur de chargement'))
.finally(() => setLoading(false));
}, [url]);
return { data, loading, error };
}
💡 Réutilisable dans tous les composants !
function UserList() {
const { data, loading, error } = useFetch<User[]>(
'https://api.example.com/users'
);
if (loading) return <p>Chargement...</p>;
if (error) return <p>{error}</p>;
return (
<ul>
{data?.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
✅ Logique de fetch extraite — composant plus lisible
Hook pour synchroniser state avec localStorage
function useLocalStorage<T>(key: string, initialValue: T) {
const [value, setValue] = useState<T>(() => {
const stored = localStorage.getItem(key);
return stored ? JSON.parse(stored) : initialValue;
});
useEffect(() => {
localStorage.setItem(key, JSON.stringify(value));
}, [key, value]);
return [value, setValue] as const;
}
💡 Persiste automatiquement les données
❌ Trop tôt
âś… Bon moment
🎯 Trouver le bon niveau d'abstraction — ni trop générique, ni trop spécifique
Le try/catch de React
Attrape les erreurs pendant le rendu
EmpĂŞche toute l'app de planter
⚠️ Les Error Boundaries DOIVENT être des composants class
class ErrorBoundary extends React.Component {
state = { hasError: false };
static getDerivedStateFromError(error: Error) {
return { hasError: true };
}
render() {
if (this.state.hasError) {
return <h1>Une erreur est survenue.</h1>;
}
return this.props.children;
}
}
<ErrorBoundary>
<MyComponent />
</ErrorBoundary>
âś… Si MyComponent plante, l'UI de fallback s'affiche
Le reste de l'application continue de fonctionner
// Placement recommandé : au niveau de la route
<Route path="/dashboard" element={
<ErrorBoundary>
<Dashboard />
</ErrorBoundary>
} />
⚠️ Ils n'attrapent que les erreurs pendant le rendu
❌ N'attrapent PAS
âś… Attrapent
đź’ˇ Pour les event handlers, utilisez try/catch classique
Organiser pour la maintenabilité
Chaque feature = son propre dossier
Avec ses composants, hooks, types, context...
❌ Par type
src/
components/
Header.jsx
UserCard.jsx
ProductList.jsx
hooks/
useUser.js
useProduct.js
Difficile de naviguer
âś… Par feature
src/
features/
user/
UserCard.jsx
useUser.js
userTypes.ts
product/
ProductList.jsx
useProduct.js
Tout est ensemble
features/
auth/
components/
LoginForm.jsx
RegisterForm.jsx
hooks/
useAuth.js
context/
AuthContext.jsx
types/
authTypes.ts
api/
authApi.js
index.js
// exports publics
đź’ˇ index.js exporte l'API publique de la feature
❌ Hooks trop génériques ou trop spécifiques
âś… Trouver le bon niveau d'abstraction
❌ Oublier que les Error Boundaries n'attrapent pas les erreurs dans les event handlers
âś… Utiliser try/catch dans les onClick, onSubmit, etc.
❌ Toute la logique dans les composants
✅ Extraire dans des custom hooks pour la réutilisabilité
❌ Ne pas typer les retours des custom hooks
âś… Utiliser TypeScript pour une meilleure DX
Custom Hook = fonction qui commence par 'use'
Extrait la logique pour la rendre réutilisable
Error Boundary
Le try/catch de React
Composant class obligatoire
Feature Folders
Chaque feature = son dossier
Composants, hooks, types ensemble
⚠️ Error Boundaries n'attrapent PAS les erreurs dans les event handlers
Custom Hooks
Extraire la logique
→ Composants plus lisibles
Error Boundaries
Attraper les crashs
→ UI de fallback
Architecture
Organiser par feature
→ Code maintenable
🎯 Prêt pour le mini-projet !
Construire une app React complète
Architecture React avancée
Mini-projet : Appliquer tous les concepts
Custom hooks + Error Boundaries + Feature folders