Nouveau : Datasets open source gratuits disponibles !Decouvrir →
⚛️
Intermediaire 25 min React

React Query avec React : guide complet

Pourquoi React Query avec React : guide complet ?

Contexte réel : pourquoi un dev a besoin de ca au quotidien

React Query est une bibliothèque populaire pour faciliter les requêtes réseau dans des applications React. Elle offre une interface simple et efficace pour récupérer, mettre à jour, supprimer et gérer les données asynchrones en utilisant des hooks personnalisés. En tant que développeur senior React avec 10+ ans d'expérience, vous avez probablement déjà affronté des problèmes comme les requêtes réseau imbriquées, la gestion des états de chargement et des erreurs, ainsi que le maintien des données synchronisées entre les composants. React Query simplifie ces tâches en offrant des outils puissants et fiables pour gérer les interactions avec les API.

Un cas d'utilisation concret en 2-3 phrases

Imaginez une application de gestion de notes où vous devez afficher les notes d'un utilisateur spécifique. Avec React Query, vous pouvez facilement récupérer les données de l'API, gérer le chargement et les erreurs, et même mettre à jour les notes en temps réel sans avoir à refaire une requête complète.

Prerequis

  • Connaissances préalables en React (Hooks, State Management)
  • Node.js v14 ou supérieur
  • npm v7 ou supérieur
  • Un environnement de développement (VSCode recommandé)

Concepts fondamentaux

1. Utilisation des hooks de base avec React Query

React Query utilise principalement les hooks useQuery et useMutation. Voici comment ils fonctionnent :

// Importer useQuery et useMutation depuis react-query
import { useQuery, useMutation } from 'react-query';

// Exemple de hook useQuery pour récupérer des données
function fetchUsers() {
  return fetch('https://api.example.com/users').then(res => res.json());
}

function UsersComponent() {
  const { isLoading, error, data: users } = useQuery('users', fetchUsers);

  if (isLoading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;

  return (
    <ul>
      {users.map(user => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}

2. Mutation et mise à jour des données

La mutation est utilisée pour effectuer des opérations CRUD (Create, Read, Update, Delete) sur les données.

// Importer useMutation depuis react-query
import { useQuery, useMutation } from 'react-query';

function fetchUsers() {
  return fetch('https://api.example.com/users').then(res => res.json());
}

function addUser(userId, userName) {
  return fetch('https://api.example.com/users', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ id: userId, name: userName })
  });
}

function UsersComponent() {
  const { isLoading, error, data: users } = useQuery('users', fetchUsers);
  const [mutate] = useMutation(addUser, {
    onSuccess: () => queryClient.invalidateQueries('users')
  });

  if (isLoading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;

  return (
    <ul>
      {users.map(user => (
        <li key={user.id}>{user.name}</li>
      ))}
      <button onClick={() => mutate(10, 'New User')}>Add New User</button>
    </ul>
  );
}

3. Gestion des erreurs et retry

React Query offre une gestion intégrée des erreurs et de la reprise automatique des requêtes.

// Importer useQuery depuis react-query
import { useQuery } from 'react-query';

function fetchUsers() {
  return fetch('https://api.example.com/users').then(res => res.json());
}

function UsersComponent() {
  const { isLoading, error, data: users } = useQuery('users', fetchUsers, {
    retry: 3,
    retryDelay: (retryCount) => Math.min(1000 * (2 ** retryCount), 60000)
  });

  if (isLoading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;

  return (
    <ul>
      {users.map(user => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}

4. Gestion des états de chargement et d'erreur

React Query gère automatiquement les états de chargement (isLoading), de succès (isSuccess) et d'erreur (isError). Vous pouvez utiliser ces états pour afficher du contenu différent en fonction de l'état actuel.

// Importer useQuery depuis react-query
import { useQuery } from 'react-query';

function fetchUsers() {
  return fetch('https://api.example.com/users').then(res => res.json());
}

function UsersComponent() {
  const { isLoading, error, data: users } = useQuery('users', fetchUsers);

  if (isLoading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;

  return (
    <ul>
      {users.map(user => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}

Mise en pratique : projet fil rouge

Construisons UN mini-projet complet et réeliste (ex: un gestionnaire de tâches, une API de blog, un scraper, un CLI tool)

Nous allons construire un simple gestionnaire de tâches avec React Query. Le projet comprendra les fonctionnalités suivantes :

  1. Afficher la liste des tâches
  2. Ajouter une nouvelle tâche
  3. Supprimer une tâche

Étape 1 : Initialisation du projet

Créez un nouveau projet React et installez React Query.

npx create-react-app task-manager
cd task-manager
npm install react-query

Étape 2 : Création des composants

Créez deux fichiers : TaskList.js et AddTask.js.

TaskList.js

// Importer useQuery et useEffect depuis react-query
import { useQuery, useEffect } from 'react-query';
import { fetchTasks, deleteTask } from './api';

function TaskList() {
  const { isLoading, error, data: tasks, refetch } = useQuery('tasks', fetchTasks);

  useEffect(() => {
    refetch();
  }, [refetch]);

  if (isLoading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;

  return (
    <ul>
      {tasks.map(task => (
        <li key={task.id}>
          {task.name}
          <button onClick={() => deleteTask(task.id)}>Delete</button>
        </li>
      ))}
    </ul>
  );
}

export default TaskList;

AddTask.js

// Importer useMutation depuis react-query
import { useMutation } from 'react-query';
import { addTask } from './api';

function AddTask({ onAdd }) {
  const [name, setName] = useState('');

  const [mutate] = useMutation(addTask, {
    onSuccess: (newTask) => {
      onAdd(newTask);
      setName('');
    }
  });

  return (
    <div>
      <input
        type="text"
        value={name}
        onChange={(e) => setName(e.target.value)}
        placeholder="Add a new task"
      />
      <button onClick={() => mutate(name)}>Add</button>
    </div>
  );
}

export default AddTask;

Étape 3 : Création des API

Créez un fichier api.js pour gérer les requêtes vers l'API.

// Importer fetch
import { fetch, deleteRequest } from 'react-query';

function fetchTasks() {
  return fetch('https://api.example.com/tasks').then(res => res.json());
}

function addTask(taskName) {
  return fetch('https://api.example.com/tasks', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ name: taskName })
  }).then(res => res.json());
}

function deleteTask(taskId) {
  return deleteRequest(`https://api.example.com/tasks/${taskId}`);
}

export { fetchTasks, addTask, deleteTask };

Étape 4 : Intégration dans le composant principal

Modifiez App.js pour intégrer les composants TaskList et AddTask.

import React from 'react';
import TaskList from './TaskList';
import AddTask from './AddTask';

function App() {
  const [tasks, setTasks] = React.useState([]);

  const handleAddTask = (newTask) => {
    setTasks([...tasks, newTask]);
  };

  return (
    <div className="App">
      <h1>Task Manager</h1>
      <AddTask onAdd={handleAddTask} />
      <TaskList />
    </div>
  );
}

export default App;

Étape 5 : Ajout des styles (optionnel)

Vous pouvez ajouter quelques styles CSS pour rendre l'application plus attrayante.

/* Dans le fichier App.css */
.App {
  text-align: center;
}

ul {
  list-style-type: none;
  padding: 0;
}

li {
  margin: 10px 0;
}

button {
  margin-left: 10px;
}

Erreurs fréquentes et debugging

1. useQuery retourne une erreur Network Error

## ❌ Mauvais
const { isLoading, error } = useQuery('users', fetchUsers);

## ✅ Correct
import axios from 'axios';

function fetchUsers() {
  return axios.get('https://api.example.com/users').then(res => res.data);
}

2. useMutation ne fonctionne pas

## ❌ Mauvais
const [mutate] = useMutation(addUser);

## ✅ Correct
import { useMutation } from 'react-query';

function AddTask({ onAdd }) {
  const [name, setName] = useState('');

  const [mutate] = useMutation(addTask, {
    onSuccess: (newTask) => {
      onAdd(newTask);
      setName('');
    }
  });

  return (
    <div>
      <input
        type="text"
        value={name}
        onChange={(e) => setName(e.target.value)}
        placeholder="Add a new task"
      />
      <button onClick={() => mutate(name)}>Add</button>
    </div>
  );
}

3. useQuery ne met pas à jour les données après la mutation

## ❌ Mauvais
const { data: tasks, refetch } = useQuery('tasks', fetchTasks);

<AddTask onAdd={() => refetch()} />

## ✅ Correct
import { useMutation, useQueryClient } from 'react-query';

function AddTask({ onAdd }) {
  const [name, setName] = useState('');
  const queryClient = useQueryClient();

  const [mutate] = useMutation(addTask, {
    onSuccess: (newTask) => {
      onAdd(newTask);
      setName('');
      queryClient.invalidateQueries('tasks');
    }
  });

  return (
    <div>
      <input
        type="text"
        value={name}
        onChange={(e) => setName(e.target.value)}
        placeholder="Add a new task"
      />
      <button onClick={() => mutate(name)}>Add</button>
    </div>
  );
}

Pour aller plus loin

1. Utilisation de useQuery avec des paramètres dynamiques

function fetchPosts(userId) {
  return fetch(`https://api.example.com/users/${userId}/posts`).then(res => res.json());
}

function UserPosts({ userId }) {
  const { isLoading, error, data: posts } = useQuery(['posts', userId], () => fetchPosts(userId));

  if (isLoading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;

  return (
    <ul>
      {posts.map(post => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  );
}

2. Utilisation de useMutation avec des hooks personnalisés

function useAddPost(userId) {
  const [mutate, { isLoading, error }] = useMutation(post => fetchPosts(userId, post), {
    onSuccess: (newPost, variables) => {
      queryClient.invalidateQueries(['posts', variables.userId]);
    }
  });

  return { addPost: mutate, isLoading, error };
}

3. Utilisation de useQuery avec des hooks personnalisés

function usePosts(userId) {
  const [query, { data, loading, error }] = useQuery(['posts', userId], () => fetchPosts(userId), {
    onSuccess: (newData) => {
      console.log('Data updated:', newData);
    }
  });

  return { posts: data, isLoading: loading, isError: !!error };
}

Défi pratique

Créez un projet de gestion simple d'utilisateurs avec les fonctionnalités suivantes :

  1. Afficher la liste des utilisateurs
  2. Ajouter un nouvel utilisateur
  3. Supprimer un utilisateur
  4. Mettre à jour les informations d'un utilisateur

Utilisez React Query pour gérer les requêtes réseau et affichez le contenu en fonction de l'état actuel (loading, error, success).

Besoin d'aide sur React ?

Besoin d'aide sur un projet technique ? Decrivez-le pour des conseils personnalises.

Recevoir des conseils

Questions frequentes

Qu'est-ce que React Query?
React Query est une bibliothèque React pour gérer les données asynchrones en composants React. Elle simplifie la récupération, le stockage et la mise à jour des données de manière réactive.
Comment installer React Query dans un projet React?
Pour installer React Query, utilisez la commande npm : 'npm install react-query' ou yarn : 'yarn add react-query'. Ensuite, importez-le dans votre application et initialisez une instance de QueryClientProvider.
Comment utiliser un query avec React Query?
Pour utiliser un query, utilisez le hook useQuery. Il prend deux arguments : une clé unique pour l'identifier le query et une fonction qui retourne une promesse résolvant les données souhaitées.

Pages liees

Chaque semaine, le meilleur de la tech francaise

Tendances, salaires, outils et opportunites — directement dans votre boite mail.

Gratuit. Desabonnement en un clic. Pas de spam.