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

React avec GraphQL

Pourquoi React avec GraphQL ?

React avec GraphQL est une combinaison puissante qui permet aux développeurs de créer des applications réactives et performantes en utilisant une API GraphQL pour récupérer les données nécessaires. En effet, GraphQL offre une grande flexibilité et un contrôle précis sur les données renvoyées par l'API. Cela signifie que chaque composant React peut demander exactement ce qu'il a besoin de savoir, sans avoir à se soucier des relations complexes ou des sous-ressources.

Un cas d'utilisation concret serait une application de messagerie instantanée où chaque utilisateur peut voir son propre flux de messages. Avec GraphQL, chaque composant ne demande que les messages du destinataire en question, ce qui réduit considérablement le temps de chargement et améliore l'expérience utilisateur.

Prerequis

  • Connaissance approfondie de React
  • Familiarité avec JavaScript ES6+
  • Compréhension des concepts d'état (state) et de props dans React
  • Connaissance de la structure de fichiers et du cycle de vie des composants React
  • Installation de Node.js v14 ou supérieur

Concepts fondamentaux

1. GraphQL : Un langage de requête pour API

GraphQL est une spécification qui définit un langage de requêtes et de mutations permettant aux clients d'interroger les données qu'ils ont besoin, sans avoir à récupérer toutes les données possibles.

## Schema GraphQL simple pour une application de tâches
type Task {
  id: ID!
  title: String!
  completed: Boolean!
}

type Query {
  tasks(filter: String): [Task]
}

2. Apollo Client : Le client GraphQL officiel pour React

Apollo Client est un client GraphQL moderne qui permet d'intégrer facilement la récupération et la mise à jour de données dans des applications React.

## Installation d'Apollo Client et des dépendances nécessaires
npm install @apollo/client graphql react-apollo-hooks

3. Queries : Requêtes pour récupérer des données

Les queries sont utilisées pour récupérer des données depuis l'API GraphQL. Elles sont spécifiées dans le composant React.

// Exemple de Query en utilisant Apollo Client
import { useQuery } from '@apollo/client';
import gql from 'graphql-tag';

const TASKS_QUERY = gql`
  query Tasks {
    tasks(filter: "") {
      id
      title
      completed
    }
  }
`;

function TaskList() {
  const { loading, error, data } = useQuery(TASKS_QUERY);

  if (loading) return <p>Chargement...</p>;
  if (error) return <p>Erreur : {error.message}</p>;

  return (
    <ul>
      {data.tasks.map(task => (
        <li key={task.id}>{task.title}</li>
      ))}
    </ul>
  );
}

4. Mutations : Mises à jour des données

Les mutations sont utilisées pour modifier les données sur le serveur, y compris la création, la mise à jour et la suppression de ressources.

// Exemple de Mutation en utilisant Apollo Client
import { useMutation } from '@apollo/client';
import gql from 'graphql-tag';

const CREATE_TASK_MUTATION = gql`
  mutation CreateTask($title: String!) {
    createTask(title: $title) {
      id
      title
      completed
    }
  }
`;

function TaskForm() {
  const [createTask, { loading, error }] = useMutation(CREATE_TASK_MUTATION);

  if (loading) return <p>Chargement...</p>;
  if (error) return <p>Erreur : {error.message}</p>;

  const handleSubmit = async event => {
    event.preventDefault();
    await createTask({ variables: { title: 'Nouvelle tâche' } });
  };

  return (
    <form onSubmit={handleSubmit}>
      <button type="submit">Créer une tâche</button>
    </form>
  );
}

5. Subscriptions : Mise à jour en temps réel

Les subscriptions sont utilisées pour écouter les événements de mise à jour en temps réel sur le serveur.

// Exemple de Subscription en utilisant Apollo Client
import { useSubscription } from '@apollo/client';
import gql from 'graphql-tag';

const NEW_TASK_SUBSCRIPTION = gql`
  subscription NewTask {
    newTask {
      id
      title
      completed
    }
  }
`;

function TaskList() {
  const { loading, error, data } = useSubscription(NEW_TASK_SUBSCRIPTION);

  if (loading) return <p>Chargement...</p>;
  if (error) return <p>Erreur : {error.message}</p>;

  return (
    <ul>
      {data.newTask ? (
        <li key={data.newTask.id}>{data.newTask.title}</li>
      ) : null}
    </ul>
  );
}

Mise en pratique : projet fil rouge

1. Configuration du projet

## Création d'un nouveau projet React
npx create-react-app react-graphql-app
cd react-graphql-app

## Installation d'Apollo Client et des dépendances nécessaires
npm install @apollo/client graphql react-apollo-hooks

2. Structure de fichiers

react-graphql-app/
├── src/
│   ├── App.js
│   ├── index.js
│   ├── TaskList.js
│   ├── TaskForm.js
│   └── tasks.graphql
└── package.json

3. Configuration d'Apollo Client

Créez un fichier ApolloClientProvider.js :

// src/ApolloClientProvider.js
import React from 'react';
import { ApolloClient, InMemoryCache, HttpLink } from '@apollo/client';

const client = new ApolloClient({
  link: new HttpLink({ uri: 'http://localhost:4000/graphql' }),
  cache: new InMemoryCache(),
});

const ApolloClientProvider = ({ children }) => (
  <ApolloProvider client={client}>
    {children}
  </ApolloProvider>
);

export default ApolloClientProvider;

4. Composants React

TaskList.js

// src/TaskList.js
import React from 'react';
import { useQuery } from '@apollo/client';
import gql from 'graphql-tag';

const TASKS_QUERY = gql`
  query Tasks {
    tasks(filter: "") {
      id
      title
      completed
    }
  }
`;

function TaskList() {
  const { loading, error, data } = useQuery(TASKS_QUERY);

  if (loading) return <p>Chargement...</p>;
  if (error) return <p>Erreur : {error.message}</p>;

  return (
    <ul>
      {data.tasks.map(task => (
        <li key={task.id}>{task.title}</li>
      ))}
    </ul>
  );
}

export default TaskList;

TaskForm.js

// src/TaskForm.js
import React from 'react';
import { useMutation } from '@apollo/client';
import gql from 'graphql-tag';

const CREATE_TASK_MUTATION = gql`
  mutation CreateTask($title: String!) {
    createTask(title: $title) {
      id
      title
      completed
    }
  }
`;

function TaskForm() {
  const [createTask, { loading, error }] = useMutation(CREATE_TASK_MUTATION);

  if (loading) return <p>Chargement...</p>;
  if (error) return <p>Erreur : {error.message}</p>;

  const handleSubmit = async event => {
    event.preventDefault();
    await createTask({ variables: { title: 'Nouvelle tâche' } });
  };

  return (
    <form onSubmit={handleSubmit}>
      <button type="submit">Créer une tâche</button>
    </form>
  );
}

export default TaskForm;

App.js

// src/App.js
import React from 'react';
import ApolloClientProvider from './ApolloClientProvider';
import TaskList from './TaskList';
import TaskForm from './TaskForm';

function App() {
  return (
    <ApolloClientProvider>
      <div className="App">
        <h1>Gestionnaire de tâches</h1>
        <TaskForm />
        <TaskList />
      </div>
    </ApolloClientProvider>
  );
}

export default App;

5. Execution du projet

## Démarrage du serveur GraphQL (supposons que votre API soit en cours d'exécution sur http://localhost:4000/graphql)
npm start

Erreurs frequentes et debugging

1. Erreur : Network error while attempting to fetch resource.

## Code incorrect
const TASKS_QUERY = gql`
  query Tasks {
    tasks(filter: "") {
      id
      title
      completed
    }
  }
`;

## Correction
const TASKS_QUERY = gql`
  query Tasks($filter: String) {
    tasks(filter: $filter) {
      id
      title
      completed
    }
  }
`;

2. Erreur : Invariant Violation: Objects are not valid as a React child.

## Code incorrect
const { data } = useQuery(TASKS_QUERY);

return (
  <ul>
    {data.tasks.map(task => (
      <li key={task.id}>{task}</li> // Problème : Tâche est un objet, pas une chaîne de caractères
    ))}
  </ul>
);

## Correction
const { data } = useQuery(TASKS_QUERY);

return (
  <ul>
    {data.tasks.map(task => (
      <li key={task.id}>{task.title}</li> // Correction : Utilisation du champ title
    ))}
  </ul>
);

3. Erreur : Invariant Violation: Can't perform a React state update on an unmounted component.

## Code incorrect
const [createTask] = useMutation(CREATE_TASK_MUTATION);

useEffect(() => {
  const subscription = someSubscription().subscribe({
    next(data) {
      createTask({ variables: { title: data.newTask.title } });
    },
  });

  return () => subscription.unsubscribe();
}, []);

## Correction
const [createTask] = useMutation(CREATE_TASK_MUTATION);

useEffect(() => {
  const subscription = someSubscription().subscribe({
    next(data) {
      if (isMounted.current) { // Vérification si le composant est toujours monté
        createTask({ variables: { title: data.newTask.title } });
      }
    },
  });

  return () => subscription.unsubscribe();
}, []);

Pour aller plus loin

1. Optimisation des requêtes avec GraphQL Fragments

Les fragments permettent de réutiliser les parties communes des requêtes.

## tasks.graphql
fragment TaskFields on Task {
  id
  title
  completed
}

query Tasks {
  tasks(filter: "") {
    ...TaskFields
  }
}

2. Intégration avec React Hooks personnalisés

Les hooks personnalisés permettent de factoriser la logique réutilisable.

// src/useTasks.js
import { useQuery } from '@apollo/client';
import gql from 'graphql-tag';

const TASKS_QUERY = gql`
  query Tasks($filter: String) {
    tasks(filter: $filter) {
      id
      title
      completed
    }
  }
`;

export default function useTasks(filter) {
  const { loading, error, data } = useQuery(TASKS_QUERY, { variables: { filter } });

  return { loading, error, tasks: data?.tasks };
}

3. Utilisation de Apollo Link pour ajouter des middleware

Les middlewares peuvent être utilisés pour intercepter les requêtes et effectuer des opérations avant ou après l'exécution.

// src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { ApolloClient, InMemoryCache, HttpLink } from '@apollo/client';

const client = new ApolloClient({
  link: new HttpLink({ uri: 'http://localhost:4000/graphql' }),
  cache: new InMemoryCache(),
});

client.use([
  ({ operation, next }, forward) => {
    console.log('Middleware : ', operation);
    return forward(operation);
  },
]);

ReactDOM.render(
  <ApolloProvider client={client}>
    <App />
  </ApolloProvider>,
  document.getElementById('root')
);

Défi pratique

Défi : Créer un mini-projet complet qui implémente la gestion des utilisateurs (CRUD) avec GraphQL et Apollo Client. Utilisez des fragments pour optimiser les requêtes et des hooks personnalisés pour factoriser la logique de récupération des données.

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 GraphQL dans le contexte de React ?
GraphQL est un langage de requêtes et un serveur de données qui permet aux clients d'obtenir exactement ce qu'ils ont besoin, en une seule requête. En combinant cela avec React, vous pouvez créer des applications plus réactives et efficaces.
Comment installer GraphQL dans un projet React ?
Pour installer GraphQL dans votre projet React, utilisez la commande `npm install graphql react-apollo @apollo/client`. Ensuite, configurez Apollo Client pour gérer les requêtes GraphQL dans votre application React.
Quelle est l'avantage de l'utilisation de GraphQL avec React ?
L'utilisation de GraphQL avec React offre plusieurs avantages, notamment une meilleure performance car elle permet d'obtenir uniquement les données nécessaires, un meilleur contrôle sur la mise à jour de l'état de l'application, et une meilleure organisation du code grâce au schéma centralisé.

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.