Fermer

mars 20, 2020

Création de tableaux triables avec React


À propos de l'auteur

Kristofer est le responsable de React chez Bekk et a travaillé sur de nombreux grands projets au cours des 6 dernières années. Il anime une rencontre de programmation basée sur la bière, essaie de garder son…
En savoir plus sur
Kristofer

Rendre vos tables triables dans React peut sembler une tâche intimidante, mais cela ne doit pas être trop difficile. Dans cet article, nous allons mettre en œuvre tout ce dont vous avez besoin pour trier tous vos besoins de tri de table.

Le tri de table a toujours été un problème assez difficile à résoudre. Il existe de nombreuses interactions à suivre, de nombreuses mutations DOM à effectuer et même des algorithmes de tri complexes. Ce n’est qu’un de ces défis difficiles à relever.

Au lieu de faire appel à des bibliothèques externes, essayons de créer nous-mêmes des choses. Dans cet article, nous allons créer un moyen réutilisable de trier vos données tabulaires dans React. Nous allons parcourir chaque étape en détail et apprendre un tas de techniques utiles en cours de route.

Nous ne passerons pas par React ou la syntaxe JavaScript de base, mais vous n'avez pas besoin d'être un expert en React pour suivre

Création d'une table avec React

Commençons par créer un exemple de composant de table. Il accepte une gamme de produits et génère un tableau très basique, répertoriant une ligne par produit.

 function ProductTable (props) {
  const {produits} = accessoires;
  revenir (
    
         {products.map (product => (
          
        ))}}
      
Nos produits
Nom Prix En stock
{product.name} {product.price} {product.stock}
); }

Ici, nous acceptons une gamme de produits et les bouclons dans notre table. C'est statique et non triable pour le moment, mais ça va pour le moment.

Tri des données

Si vous croyez tous les enquêteurs du tableau blanc, vous penseriez que le développement de logiciels était presque tous des algorithmes de tri. Heureusement, nous ne chercherons pas ici un tri rapide ou un tri à bulles.

Le tri des données en JavaScript est assez simple, grâce à la fonction de tableau intégrée sort () . Il triera les tableaux de nombres et de chaînes sans argument supplémentaire:

 const array = ['mozzarella', 'gouda', 'cheddar'];
array.sort ();
console.log (tableau); // ['cheddar', 'gouda', 'mozzarella'] 

Si vous voulez quelque chose d'un peu plus intelligent, vous pouvez lui passer une fonction de tri. Cette fonction se voit attribuer deux éléments dans la liste en tant qu'arguments, et placera l'un devant l'autre en fonction de ce que vous déciderez.

Commençons par trier les données que nous obtenons par ordre alphabétique par nom.

 function ProductTable (props) {
  const {produits} = accessoires;
  laissez sortedProducts = [...products];
  sortedProducts.sort ((a, b) => {
    if (a.name  b.name) {
      retour 1;
    }
    retourner 0;
  });
  revenir (
    
      {/* comme avant */}
    
  ); }

Alors, que se passe-t-il ici? Tout d'abord, nous créons une copie de l'accessoire des produits, que nous pouvons modifier et changer à notre guise. Nous devons le faire car la fonction Array.prototype.sort modifie le tableau d'origine au lieu de renvoyer une nouvelle copie triée.

Ensuite, nous appelons sortedProducts.sort et passons c'est une fonction de tri . Nous vérifions si la propriété nom du premier argument a est antérieure au deuxième argument b et si c'est le cas, renvoyons une valeur négative. Cela indique que a devrait précéder b dans la liste. Si le nom du premier argument est après le nom du deuxième argument, nous renvoyons un nombre positif, indiquant que nous devons placer b avant a . Si les deux sont égaux (c'est-à-dire que les deux ont le même nom), nous renvoyons 0 pour conserver l'ordre.

Rendre notre table triable

Nous pouvons donc maintenant nous assurer que la table est triée par nom – mais comment pouvons-nous changer l'ordre de tri nous-mêmes?

Pour changer le champ par lequel nous trions, nous devons nous souvenir du champ actuellement trié. Nous le ferons avec le crochet useState .

Un crochet est un type spécial de fonction qui nous permet de «nous accrocher» à certaines des fonctionnalités de base de React, comme la gestion de l'état et le déclenchement d'effets secondaires. Ce crochet particulier nous permet de maintenir un morceau d'état interne dans notre composant et de le changer si nous le voulons. Voici ce que nous ajouterons:

 const [sortedField, setSortedField] = React.useState (null); 

Nous commençons par ne rien trier du tout. Ensuite, modifions les en-têtes de table pour inclure un moyen de changer le champ par lequel nous voulons trier.

 const ProductsTable = (props) => {
  const {produits} = accessoires;
  const [sortedField, setSortedField] = React.useState (null);
  revenir (
    
       {/ * Comme précédemment * /}
    
                                               
  ); };

Désormais, chaque fois que nous cliquons sur un en-tête de tableau, nous mettons à jour le champ selon lequel nous voulons trier. Neat-o!

Cependant, nous ne faisons pas encore de tri réel, alors corrigeons cela. Rappelez-vous l'algorithme de tri d'avant? Le voici, légèrement modifié pour fonctionner avec n'importe lequel de nos noms de champs.

 const ProductsTable = (props) => {
  const {produits} = accessoires;
  const [sortedField, setSortedField] = React.useState (null);
  laissez sortedProducts = [...products];
  if (sortedField! == null) {
    sortedProducts.sort ((a, b) => {
      si (a [sortedField]   b [sortedField]) {
        retour 1;
      }
      retourner 0;
    });
  }
  revenir (
    

Nous nous assurons d'abord que nous avons choisi un champ de tri, et si c'est le cas, nous trions les produits par ce champ.

Croissant vs Décroissant

La prochaine fonctionnalité que nous voulons voir est un façon de basculer entre l'ordre croissant et décroissant. Nous allons basculer entre l'ordre croissant et décroissant en cliquant une nouvelle fois sur l'en-tête du tableau.

Pour implémenter cela, nous devons introduire un deuxième élément d'état – l'ordre de tri. Nous allons refactoriser notre variable d'état sortedField actuelle pour conserver à la fois le nom du champ et sa direction. Au lieu de contenir une chaîne, cette variable d'état contiendra un objet avec une clé (le nom du champ) et une direction. Nous allons le renommer en sortConfig pour être un peu plus clair.

Voici la nouvelle fonction de tri:

 sortedProducts.sort ((a, b) => {
  if (a [sortConfig.key]   b [sortConfig.key]) {
    retourner sortConfig.direction === 'croissant'? 1: -1;
  }
  retourner 0;
}); 

Maintenant, si la direction est "ascendante", nous ferons comme nous l'avons fait précédemment. Si ce n'est pas le cas, nous ferons le contraire, en nous donnant un ordre décroissant.

Ensuite, nous allons créer une nouvelle fonction – requestSort – qui acceptera le nom du champ et mettra à jour l'état en conséquence .

 const requestSort = key => {
  let direction = 'ascendant';
  if (sortConfig.key === key && sortConfig.direction === 'ascendant') {
    direction = 'descendant';
  }
  setSortConfig ({clé, direction});
} 

Nous devrons également modifier nos gestionnaires de clics pour utiliser cette nouvelle fonction!

 return (
  
{/ * comme avant * /}   

Maintenant, nous commençons à avoir l'air assez complet, mais il reste encore une grande chose à faire. Nous devons nous assurer de ne trier nos données que lorsque nous en avons besoin. Actuellement, nous trions toutes nos données sur chaque rendu, ce qui entraînera toutes sortes de problèmes de performances sur toute la ligne. À la place, utilisons le crochet useMemo intégré pour mémoriser toutes les parties lentes!

 const ProductsTable = (props) => {
  const {produits} = accessoires;
  const [sortConfig, setSortConfig] = React.useState (null);
  
  React.useMemo (() => {
    laissez sortedProducts = [...products];
    if (sortedField! == null) {
      sortedProducts.sort ((a, b) => {
        si (a [sortConfig.key]   b [sortConfig.key]) {
          retourner sortConfig.direction === 'croissant'? 1: -1;
        }
        retourner 0;
      });
    }
    return sortedProducts;
  }, [products, sortConfig]); 

Si vous ne l'avez jamais vu auparavant, useMemo est un moyen de mettre en cache – ou de mémoriser – des calculs coûteux. Donc, étant donné la même entrée, il n'est pas nécessaire de trier les produits deux fois si nous restituons notre composant pour une raison quelconque. Notez que nous voulons déclencher un nouveau tri chaque fois que nos produits changent, ou le champ ou la direction que nous trions par changements.

Envelopper notre code dans cette fonction aura d'énormes implications en termes de performances pour notre tri de table!

Rendre tout cela réutilisable

L'une des meilleures choses à propos des crochets est la facilité avec laquelle il est possible de rendre la logique réutilisable. Vous allez probablement trier tous les types de tableaux dans votre application, et devoir réimplémenter à nouveau les mêmes éléments ressemble à une traînée.

React a cette fonctionnalité appelée crochets personnalisés . Ils semblent fantaisistes, mais ce ne sont que des fonctions régulières qui utilisent d'autres crochets à l'intérieur d'eux. Refactorisons notre code pour qu'il soit contenu dans un hook personnalisé, afin que nous puissions l'utiliser partout!

 const useSortableData = (items, config = null) => {
  const [sortConfig, setSortConfig] = React.useState (config);
  
  const sortedItems = React.useMemo (() => {
    laissez sortableItems = [...items];
    if (sortConfig! == null) {
      sortableItems.sort ((a, b) => {
        si (a [sortConfig.key]   b [sortConfig.key]) {
          retourner sortConfig.direction === 'croissant'? 1: -1;
        }
        retourner 0;
      });
    }
    return sortableItems;
  }, [items, sortConfig]);

  const requestSort = key => {
    let direction = 'ascendant';
    if (sortConfig && sortConfig.key === clé && sortConfig.direction === 'ascendant') {
      direction = 'descendant';
    }
    setSortConfig ({clé, direction});
  }

  renvoyer {items, requestSort};
} 

Ceci est à peu près un copier-coller de notre code précédent, avec un peu de changement de nom. useSortableData accepte les éléments et un état de tri initial facultatif. Il renvoie un objet avec les éléments triés et une fonction pour trier à nouveau les éléments.

Notre code de table ressemble maintenant à ceci:

 const ProductsTable = (props) => {
  const {produits} = accessoires;
  const {items, requestSort} = useSortableData (produits);
  revenir (
     {/ * ... * /} 
  ); };

A Last Touch

Il manque une toute petite pièce – un moyen d'indiquer comment la table est triée. Afin d'indiquer que dans notre conception, nous devons également renvoyer l'état interne – le sortConfig . Rendons cela également et utilisons-le pour générer des styles que nous pouvons appliquer à nos en-têtes de tableau!

 const ProductTable = (props) => {
  const {items, requestSort, sortConfig} = useSortableData (props.products);
  const getClassNamesFor = (nom) => {
    if (! sortConfig) {
      revenir;
    }
    retourner sortConfig.key === nom? sortConfig.direction: undefined;
  };
  revenir (
    
          {/ *… * /}
        
       {/ *… * /}
    
Produits
            
  ); };

Et avec cela, nous avons terminé!

Conclusion

En fait, créer votre propre algorithme de tri de table n'était pas un exploit impossible après tout. Nous avons trouvé un moyen de modéliser notre état, nous avons écrit une fonction de tri générique et nous avons écrit un moyen de mettre à jour nos préférences de tri. Nous nous sommes assurés que tout était performant et avons refactorisé le tout dans un crochet personnalisé. Enfin, nous avons fourni un moyen d'indiquer l'ordre de tri à l'utilisateur.

Vous pouvez voir une démonstration du tableau dans ce CodeSandbox :

 Éditorial Smashing (ra, yk, il )




Source link
Revenir vers le haut