Récupérer et définir les query params avec React Router(+ hook personnalisé)
18 avr. 2024
Table des matières:
- Pourquoi utiliser les query params avec React Router
- Définir les query params
- Récupérer les query params
- 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 objetexport 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 paramsfunction 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 objetfunction 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";// utilsimport { 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
etqueryStringToObject
, 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.
Partager cet article:
Coach à Bakeli School of Technology