Programmation

Récupérer et définir les query params avec React Router(+ hook personnalisé)

18 avr. 2024

Table des matières:

  1. Pourquoi utiliser les query params avec React Router
  2. Définir les query params
  3. Récupérer les query params
  4. Le hook personnalisé useQueryParams

J’ai créé un hook personnalisé pour récupérer et définir les query params dans un URL avec de React Router. Voici comment (et pourquoi) je l’ai fais, avec tout le code dont vous avez besoin pour l’utiliser.

Aujourd’hui, je retravaillais sur un composant de recherche avec ReactJS pour une page d’offres. Lorsque vous accédez à cette page, vous avez toutes les offres, et vous pouvez effectuer une recherche par nom ou par un autre filtre.

La recherche a fonctionné, mais une fois que vous avez cliqué sur un résultat (une offre), si vous avez cliqué sur le bouton précédent du navigateur, vous reviendrez à tous les résultats (plutôt qu’aux résultats de recherche filtrés).

Ce qui ne semblait pas bien.

J’ai résolu ce problème en utilisant les query params

Je créé un hook personnalisé (réutilisable) afin de pouvoir l’utiliser pour tout composant qui devra interagir avec les query params à l’avenir.

Pourquoi utiliser les query params avec React Router

Allez rechercher « query params » dans Google et vous verrez dans la barre d’adresse qu’un query params a été ajoutée à l’URL.

<https://www.google.com/search?q=query+params>

Tout ce qui vient après le ? est votre query params - dans notre cas q=query+params.

Je n’ai jamais vraiment été un grand utilisateur des query params dans les applications Web que j’ai développée. J’ai appris à coder lorsque les frameworks JavaScript (en particulier les applications monopage comme React) devenaient populaires, et je gérais l’état dans Redux, React State ou React Context.

Mais je commence à apprendre que les query params sont très utiles, en particulier pour des actions telles que la recherche, qui peuvent vous maintenir sur la même page mais afficher des contextes différents en fonction des valeurs saisies par l’utilisateur.

Si les valeurs sont stockées dans l’état du composant, lorsque l’utilisateur quitte le composant, les valeurs précédentes disparaissent. Mais s’ils sont stockés sous forme de paires clé-valeur dans une chaîne de requête sur l’URL, revenir dans le navigateur peut restaurer les valeurs précédentes.

Il nous suffit de définir et de récupérer les query params !

Définir les query params

Dans React Router, location représente l’endroit où se trouve l’application. Nous ne voulons pas modifier le chemin d’accès, mais nous souhaitons ajouter des query params à l’URL. Dans React Router, c’est sur location.search

Vous pouvez utiliser le hook useNavigate pour naviguer, ce qui stockera le query params dans l’historique du navigateur (afin que le bouton Précédent du navigateur fonctionne).

import React from 'react';
import { useNavigate } from 'react-router-dom'
 
function SearchComponent(props) {
const navigate = useNavigate();
 
// Mettre à jour les query params
function setQueryParams() {
navigate({
search: "?page=1&text=john"
});
};
};

Cela fonctionne très bien, mais nous ne voulons pas coder en dur le query params"?page=1&text=john" car elle doit prendre des données réelles. Idéalement, j’aimerais lui transmettre un objet et il sera transformé en query params par magie (ou code).

Maintenant, je peux utiliser URLSearchParams pour cela, mais il n’est pas pris en charge dans Internet Explorer que certaines personnes utilisent encore 🙄, donc pour plus de tranquillité d’esprit, j’ai créé une fonction pour le faire.

// Crée une chaîne de requête à partir d'un objet
export function createQueryString(queryObject = {}) {
let queryString = Object.keys(queryObject)
.filter(
(key) =>
queryObject[key] &&
!(Array.isArray(queryObject[key]) && !queryObject[key].length)
)
.map((key) => {
return Array.isArray(queryObject[key])
? queryObject[key]
.map(
(item) => `${encodeURIComponent(key)}=${encodeURIComponent(item)}`
)
.join("&")
: `${encodeURIComponent(key)}=${encodeURIComponent(queryObject[key])}`;
})
.join("&");
return queryString ? `?${queryString}` : "";
}

Ceci va .filtrer() toutes les valeurs ou tableaux vides et transformera le reste en query params.

Voyons-le en action !

console.log(createQueryString({ page: 1, text: "john" }));
// "?page=1&text=john"
 
console.log(createQueryString({ page: 1, text: "" }));
// "?page=1"
 
console.log(
createQueryString({ page: 1, text: "", department: ["hr", "accounts"] })
);
// "?page=1&department=hr&department=accounts"
 
console.log(createQueryString({ page: 1, text: "", department: [] }));
// "?page=1"

Je peux passer un objet à setQueryParams et, à l’aide de la fonction createQueryString, le transformer en query params dans la barre d’adresse.

// Mettre à jour les query params
function setQueryParams(queryObj) {
navigate({
search: createQueryString(queryObj)
});
};

Récupérer les query params

Je peux maintenant utiliser setQueryParams pour définir mon query params, mais mon composant devra également récupérer mon query params et le transformer en objet, ainsi, lorsque je navigue sur une autre page, mon composant sait quelles valeurs utiliser.

Pour ce faire, je peux utiliser useLocation et obtenir la recherche à partir de l’objet location.

import React from 'react';
import { useLocation, useNavigate } from 'react-router-dom'
 
function SearchComponent(props) {
const navigate = useNavigate();
const { search } = useLocation(); // Obtenir la recherche à partir de l'objet location
 
const queryParams = React.useMemo(() => search, [search]);
 
//...
};

C’est dans useMemo() donc l’objet queryParams n’est mis à jour que lorsque location.search change dans useLocation(). Utile si la modification des query params lance des requêtes API.

Cela me donne le query params, par exemple. "?page=1&text=john", mais bien sûr, je veux transformer cela en un objet.

Encore une fois, je peux utiliser URLSearchParams pour cela, mais j’ai créé une fonction personnalisée pour mon propre usage.

// Transforme les query params en objet
function queryStringToObject(queryString = "", options = {}) {
let queryObject = {};
queryString &&
decodeURIComponent(queryString.replace("?", ""))
.split("&")
.map((itemString) => {
let [itemKey, itemValue] = itemString.split("=");
if (options.hasOwnProperty(itemKey)) {
if (!queryObject[itemKey] && Array.isArray(options[itemKey])) {
queryObject[itemKey] = [];
}
Array.isArray(options[itemKey])
? queryObject[itemKey].push(itemValue)
: (queryObject[itemKey] =
typeof options[itemKey] === "number"
? parseInt(itemValue)
: itemValue);
}
});
return queryObject;
}

Cela fonctionne comme ceci :

console.log(
queryStringToObject("?page=1&department=hr&department=accounts", {
page: 0,
department: [],
})
);
 
// {
// page: 1,
// department: ['hr', 'accounts']
// }

La fonction queryStringToObject prend un query params et un objet d’options qui lui indique les valeurs par défaut (si aucune valeur n’est dans le query params) - cela est nécessaire pour que la fonction connaisse le type de valeur. Ce qui est particulièrement utile lorsque nous voulons utiliser des tableaux ou des valeurs numériques.

Par exemple, s’il n’y avait qu’une seule paire clé-valeur department dans le query params, je souhaiterais toujours récupérer un tableau plutôt qu’une chaîne, car ces données doivent être un tableau.

console.log(
queryStringToObject("?page=1&department=hr", { page: 0, department: [] })
);
 
// {
// page: 1,
// department: ['hr']
// }

Je peux maintenant mettre à jour le hook useMemo pour utiliser la fonction queryStringToObject.

const queryParams = React.useMemo(
() => queryStringToObject(search, { page: 0, department: [] }),
[search]
);

Le hook personnalisé useQueryParams

Maintenant que je peux définir et récupérer mes query params, je vais le déplaçer dans un hook personnalisé qui pourra être utilisé par n’importe quel composant à l’avenir.

Je l’ai appellé useQueryParams.js

import React from "react";
import { useLocation, useNavigate } from "react-router-dom";
// utils
import { createQueryString, queryStringToObject } from "../utils/createQueryString";
 
function useQueryParams() {
const { search } = useLocation();
const navigate = useNavigate();
 
// Récupérer les query params
const queryParams = React.useMemo(
() => queryStringToObject(search, options),
[search]
);
 
// Mettre à jour les query params
function setQueryParams(queryObj) {
// queryParams.set(queryName, queryObj);
navigate({
// search: queryParams.toString(),
search: createQueryString(queryObj),
});
}
 
return { queryParams, setQueryParams };
}
 
export default useQueryParams;

N’oubliez pas d’inclure les fonctions createQueryString et queryStringToObject, ou de les importer à partir d’un fichier différent comme je l’ai fait ci-dessus.

Je peux désormais utiliser le hook personnalisé dans n’importe quel composant React où j’ai besoin de récupérer ou de définir des query params. Voici à quoi cela ressemble dans mon composant de recherche.

import React from 'react';
import useQueryParams from "../../hooks/useQueryParams";
 
function SearchComponent(props) {
const { queryParams, setQueryParams } = useQueryParams({ page: 0, department: [] });
 
// Requête api
React.useEffect(() => {
searchAPI(queryParams).then((results) => {
// faire quelque chose avec les résultats
}
}, [queryParams]);
 
// Mettre à jour les query params
function handleSearch({ title, department }) {
setQueryParams({
...(title && { title }),
...(department && { department }),
});
};
};

Ceci montre comment fonctionne le hook. Lorsque handleSearch est appelé, à partir d’une recherche saisie par l’utilisateur, un objet de recherche est créé (dans cet exemple, avec les clés title et/ou department mais toutes les clés peuvent être utilisées selon les besoins de votre cas d’utilisation).

Les valeurs sont ajoutées en tant que query params à l’emplacement, par setQueryParams, qui mettra ensuite à jour queryParams et déclenchera une nouvelle requête API. Vous pouvez remplacer ce useEffect par un useQuery si vous utilisez React Query.

Mountaga Diao Leye Diop

Coach à Bakeli School of Technology

Bakeli est une école de formation professionnelle dans les nouvelles technologies créer par Volkeno. Elle a formé + de 6000 étudiants et professionnels aux métiers des nouvelles technologies et du digital.

Bakeli

Contacts

S'abonner à la Newsletter

Chargement en cours...

© Copyright 2024, Tous droits réservés.