Nouveau : Datasets open source gratuits disponibles !Decouvrir →
Web 12 min intermediaire

Les erreurs a eviter en Next.js

Sommaire

Erreur 1 : Utilisation inappropriée de la fonction useEffect pour des tâches asynchrones

Le problème

La fonction useEffect est souvent utilisée pour effectuer des opérations asynchrones comme les appels API, mais elle n'est pas conçue pour gérer les exceptions et peut causer des problèmes de mémorisation si elle est utilisée de manière incorrecte.

import { useEffect } from 'react';

function MyComponent() {
  useEffect(() => {
    fetch('https://api.example.com/data')
      .then(response => response.json())
      .then(data => {
        // Manipulation des données
      })
      .catch(error => {
        console.error('Error fetching data:', error);
      });
  }, []); // Empty dependency array leads to unnecessary re-fetches on every render
}

Pourquoi c'est une erreur

L'utilisation de useEffect pour des appels asynchrones peut entraîner un comportement inattendu, comme des mises à jour répétées de l'état ou des re-rendus indésirables. Les exceptions non gérées peuvent également causer des problèmes de performance et de sécurité.

La solution

Utilisez useEffect avec une fonction asynchrone dans un bloc try-catch pour gérer les erreurs et utilisez useState pour stocker les données récupérées.

import { useEffect, useState } from 'react';

function MyComponent() {
  const [data, setData] = useState(null);
  const [error, setError] = useState(null);

  useEffect(() => {
    async function fetchData() {
      try {
        const response = await fetch('https://api.example.com/data');
        if (!response.ok) {
          throw new Error('Network response was not ok');
        }
        const result = await response.json();
        setData(result);
      } catch (err) {
        setError(err.message);
      }
    }

    fetchData(); // Call the fetchData function inside useEffect
  }, []); // Empty dependency array ensures this effect runs only once after the initial render

  if (error) {
    return <div>Error: {error}</div>;
  }

  return (
    <div>
      {/* Render data or loading state */}
    </div>
  );
}

Comment prévenir

  • Assurez-vous que les appels asynchrones sont placés dans une fonction interne à useEffect.
  • Utilisez un bloc try-catch pour gérer les erreurs.
  • Limitez le nombre de dépendances dans le tableau du second argument de useEffect.

Erreur 2 : Manque d'optimisation des composants avec React.memo

Le problème

Les composants fonctionnels React ne sont pas optimisés par défaut. Si une prop est immutable et ne change pas souvent, il peut être inefficace de re-render un composant.

import { memo } from 'react';

const MyComponent = ({ data }) => {
  return (
    <div>
      {data.map(item => (
        <Item key={item.id} item={item} />
      ))}
    </div>
  );
};

export default memo(MyComponent);

Pourquoi c'est une erreur

Le wrapping de MyComponent avec memo n'optimise pas les rendus inutiles. Si le contenu des items change fréquemment, même si l'identifiant est constant, chaque item sera re-render.

La solution

Utilisez React.memo avec une fonction de comparaison personnalisée pour éviter les re-rendus inutiles.

import { memo } from 'react';

const areItemsEqual = (prevProps, nextProps) => {
  return prevProps.data.length === nextProps.data.length && 
         prevProps.data.every((item, index) => item.id === nextProps.data[index].id);
};

const MyComponent = ({ data }) => {
  return (
    <div>
      {data.map(item => (
        <Item key={item.id} item={item} />
      ))}
    </div>
  );
};

export default memo(MyComponent, areItemsEqual);

Comment prévenir

  • Utilisez React.memo pour les composants qui ont des props complexes.
  • Implémentez une fonction de comparaison personnalisée pour les props qui nécessitent une optimisation spécifique.

Erreur 3 : Manque d'utilisation du contexte

Le problème

Les états globaux peuvent être gérés avec useState ou useReducer, mais cela peut entraîner des performances dégradées si ces états sont utilisés dans de nombreux composants imbriqués.

const App = () => {
  const [user, setUser] = useState({ name: 'John' });

  return (
    <div>
      <UserProfile />
      <Settings />
    </div>
  );
};

const UserProfile = ({ user }) => {
  // Utilisation de la prop user
  return <p>User: {user.name}</p>;
};

const Settings = () => {
  const [theme, setTheme] = useState('light');
  // Manipulation du state local theme

  return (
    <div>
      <h1>Settings</h1>
    </div>
  );
};

Pourquoi c'est une erreur

Le re-render de composants imbriqués peut entraîner des performances dégradées, surtout si le contexte est grand ou modifié souvent.

La solution

Utilisez useContext pour partager les états globaux et React.memo pour éviter les re-rendus inutiles.

import { createContext, useContext, useState } from 'react';

const UserContext = createContext();

const App = () => {
  const [user, setUser] = useState({ name: 'John' });

  return (
    <UserContext.Provider value={user}>
      <div>
        <UserProfile />
        <Settings />
      </div>
    </UserContext.Provider>
  );
};

const UserProfile = memo(() => {
  const user = useContext(UserContext);
  
  // Utilisation du contexte
  return <p>User: {user.name}</p>;
});

const Settings = () => {
  const [theme, setTheme] = useState('light');
  
  // Manipulation du state local theme

  return (
    <div>
      <h1>Settings</h1>
    </div>
  );
};

Comment prévenir

  • Utilisez useContext pour partager les états globaux.
  • Implémentez des composants avec React.memo pour éviter les re-rendus inutiles.

Erreur 4 : Manque d'utilisation de la fonction useReducer pour gérer des états complexes

Le problème

Les états simples peuvent être gérés avec useState, mais lorsque l'état devient complexe et nécessite une logique de gestion réactive, il est préférable d'utiliser useReducer.

const [state, setState] = useState({ count: 0, items: [] });

const handleClick = () => {
  setState(prevState => ({
    ...prevState,
    count: prevState.count + 1
  }));
};

Pourquoi c'est une erreur

La gestion manuelle de l'état complexe avec useState peut conduire à des erreurs difficiles à déboguer et à un code difficile à maintenir.

La solution

Utilisez useReducer pour gérer les états complexes et centraliser la logique de mise à jour.

import { useReducer } from 'react';

const initialState = { count: 0, items: [] };

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { ...state, count: state.count + 1 };
    case 'add_item':
      return { ...state, items: [...state.items, action.payload] };
    default:
      throw new Error();
  }
}

const App = () => {
  const [state, dispatch] = useReducer(reducer, initialState);

  const handleClick = () => {
    dispatch({ type: 'increment' });
  };

  const addItem = (item) => {
    dispatch({ type: 'add_item', payload: item });
  };

  return (
    <div>
      Count: {state.count}
      <button onClick={handleClick}>Increment</button>
      <ul>
        {state.items.map(item => (
          <li key={item.id}>{item.name}</li>
        ))}
      </ul>
      <button onClick={() => addItem({ id: Date.now(), name: 'New Item' })}>
        Add Item
      </button>
    </div>
  );
};

Comment prévenir

  • Utilisez useReducer pour gérer les états complexes et centraliser la logique de mise à jour.
  • Assurez-vous que la logique de réduction est claire et testée.

Erreur 5 : Manque d'utilisation des hooks personnalisés

Le problème

La duplication du code est fréquente dans les composants React, surtout pour la gestion des états complexes ou des interactions avec l'API. Les hooks personnalisés peuvent aider à factoriser ce code et le rendre plus réutilisable.

const useFetch = (url) => {
  const [data, setData] = useState(null);
  const [error, setError] = useState(null);

  useEffect(() => {
    async function fetchData() {
      try {
        const response = await fetch(url);
        if (!response.ok) {
          throw new Error('Network response was not ok');
        }
        const result = await response.json();
        setData(result);
      } catch (err) {
        setError(err.message);
      }
    }

    fetchData(); // Call the fetchData function inside useEffect
  }, [url]); // Dependency array to re-fetch data when url changes

  return { data, error };
};

Pourquoi c'est une erreur

La duplication de code peut entraîner des erreurs difficiles à déboguer et à un code difficile à maintenir. Les hooks personnalisés permettent d'abstraire la logique de réutilisation.

La solution

Créez des hooks personnalisés pour gérer les interactions avec l'API ou la gestion des états complexes.

import { useState, useEffect } from 'react';

const useFetch = (url) => {
  const [data, setData] = useState(null);
  const [error, setError] = useState(null);

  useEffect(() => {
    async function fetchData() {
      try {
        const response = await fetch(url);
        if (!response.ok) {
          throw new Error('Network response was not ok');
        }
        const result = await response.json();
        setData(result);
      } catch (err) {
        setError(err.message);
      }
    }

    fetchData(); // Call the fetchData function inside useEffect
  }, [url]); // Dependency array to re-fetch data when url changes

  return { data, error };
};

const MyComponent = () => {
  const { data, error } = useFetch('https://api.example.com/data');

  if (error) {
    return <div>Error: {error}</div>;
  }

  return (
    <div>
      {/* Render data or loading state */}
    </div>
  );
};

Comment prévenir

  • Créez des hooks personnalisés pour gérer la logique de réutilisation.
  • Assurez-vous que les hooks personnalisés sont documentés et testés.

Erreur 6 : Manque d'utilisation du suspense avec React.lazy et Suspense

Le problème

Les composants asynchrones peuvent entraîner des temps morts pendant le rendu initial. La gestion manuelle de ces cas peut être complexe et les erreurs difficiles à déboguer.

const OtherComponent = React.lazy(() => import('./OtherComponent'));

const App = () => {
  return (
    <div>
      <h1>Welcome</h1>
      <Suspense fallback={<div>Loading...</div>}>
        <OtherComponent />
      </Suspense>
    </div>
  );
};

Pourquoi c'est une erreur

La gestion manuelle de la suspension peut entraîner des performances dégradées et des erreurs difficiles à déboguer. Le suspense avec React.lazy permet de gérer les composants asynchrones de manière plus simple et efficace.

La solution

Utilisez React.lazy et Suspense pour gérer les composants asynchrones.

import { lazy, Suspense } from 'react';

const OtherComponent = lazy(() => import('./OtherComponent'));

const App = () => {
  return (
    <div>
      <h1>Welcome</h1>
      <Suspense fallback={<div>Loading...</div>}>
        <OtherComponent />
      </Suspense>
    </div>
  );
};

Comment prévenir

  • Utilisez React.lazy et Suspense pour gérer les composants asynchrones.
  • Assurez-vous que le fallback est clair et accueillant.

Erreur 7 : Manque d'utilisation de la fonction useCallback pour optimiser des callbacks

Le problème

Les callbacks peuvent entraîner des re-rendus inutiles si ils ne sont pas correctement optimisés. Cela peut causer une performance dégradée, surtout dans des composants imbriqués.

const MyComponent = ({ onClick }) => {
  const handleClick = () => {
    onClick();
  };

  return (
    <button onClick={handleClick}>
      Click me
    </button>
  );
};

Pourquoi c'est une erreur

La création d'une fonction handleClick à chaque rendu peut entraîner des re-rendus inutiles des composants parents qui dépendent de ce callback.

La solution

Utilisez useCallback pour optimiser les callbacks et éviter les re-rendus inutiles.

import { useCallback } from 'react';

const MyComponent = ({ onClick }) => {
  const handleClick = useCallback(() => {
    onClick();
  }, [onClick]); // Dependency array to ensure the callback is only recreated when onClick changes

  return (
    <button onClick={handleClick}>
      Click me
    </button>
  );
};

Comment prévenir

  • Utilisez useCallback pour optimiser les callbacks.
  • Assurez-vous que le tableau de dépendances est bien défini.

Erreur 8 : Manque d'utilisation du contexte avec des composants conditionnels

Le problème

La gestion manuelle des états globaux peut être complexe, surtout dans des structures de composants conditionnelles. Utiliser le contexte peut simplifier cette gestion.

const App = () => {
  const [user, setUser] = useState({ name: 'John' });

  return (
    <div>
      {user ? (
        <UserProfile user={user} />
      ) : (
        <Login setUser={setUser} />
      )}
    </div>
  );
};

Pourquoi c'est une erreur

La gestion manuelle des états globaux peut entraîner des erreurs difficiles à déboguer et un code difficile à maintenir. Utiliser le contexte permet de gérer les états globaux plus facilement.

La solution

Utilisez useContext pour partager les états globaux dans des structures de composants conditionnelles.

import { createContext, useContext } from 'react';

const UserContext = createContext();

const App = () => {
  const [user, setUser] = useState({ name: 'John' });

  return (
    <UserContext.Provider value=user, setUser>
      <div>
        {user ? <UserProfile /> : <Login />}
      </div>
    </UserContext.Provider>
  );
};

const UserProfile = () => {
  const { user } = useContext(UserContext);
  
  // Utilisation du contexte
  return <p>User: {user.name}</p>;
};

const Login = ({ setUser }) => {
  const handleLogin = (newUser) => {
    setUser(newUser);
  };

  return (
    <div>
      {/* Form to login */}
    </div>
  );
};

Comment prévenir

  • Utilisez useContext pour partager les états globaux dans des structures de composants conditionnelles.
  • Assurez-vous que le contexte est bien documenté et testé.

Un projet tech a lancer ?

Besoin d'un accompagnement ? Decrivez votre projet pour des recommandations.

Recevoir des conseils

Questions frequentes

Quelle est la différence entre 'next.config.js' et '_app.js' en Next.js?
'next.config.js' est utilisé pour configurer des options globales de Next.js, tandis que '_app.js' est un composant universel qui s'enroule autour de chaque page.
Comment éviter les erreurs liées aux routes dynamiques en Next.js?
Assurez-vous d'avoir une route dynamique correctement configurée avec l'extension appropriée ('[slug].js') et de gérer correctement les cas où le slug est manquant.
Quelle est la meilleure pratique pour gérer les erreurs en production dans Next.js?
Utilisez le composant 'Error Boundary' pour capturer et afficher des erreurs, puis configurez un système de logging pour surveiller et diagnostiquer les erreurs en temps réel.

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.