React - Comment obtenir la valeur d'un paramètre à partir d'une chaîne de requête

413

Comment puis-je définir un itinéraire dans mon fichier routes.jsx pour capturer la __firebase_request_keyvaleur du paramètre à partir d'une URL générée par le processus d'authentification unique de Twitter après la redirection depuis leurs serveurs?

http://localhost:8000/#/signin?_k=v9ifuf&__firebase_request_key=blablabla

J'ai essayé avec la configuration des itinéraires suivante, mais le :redirectParamn'attrape pas le paramètre mentionné:

<Router>
  <Route path="/" component={Main}>
    <Route path="signin" component={SignIn}>
      <Route path=":redirectParam" component={TwitterSsoButton} />
    </Route>
  </Route>
</Router>
Franco
la source
1
Il y a une discussion Github ici
vsync
3
regrettable que la question dise "chaînes de requête" mais pose en fait sur les "paramètres d'URL"
SeanMC
6
query strings"? var1 = val & var2 = val2",: url paramters"/ photos /: companyiD / new"
Maddocks

Réponses:

484

React Router v3

React Router analyse déjà l'emplacement pour vous et le transmet à votre RouteComponent comme accessoire. Vous pouvez accéder à la partie requête (après? Dans l'url) via

this.props.location.query.__firebase_request_key

Si vous recherchez les valeurs des paramètres de chemin, séparées par deux points (:) à l'intérieur du routeur, celles-ci sont accessibles via

this.props.match.params.redirectParam

Cela s'applique aux dernières versions de React Router v3 (je ne sais pas laquelle). Des versions de routeur plus anciennes auraient été utilisées this.props.params.redirectParam.

React Router v4 et React Router v5, génériques

React Router v4 n'analyse plus la requête pour vous, mais vous ne pouvez y accéder que via this.props.location.search. Pour des raisons, voir la réponse de nbeuchat .

Par exemple, avec la bibliothèque qs importée comme qsvous pourriez le faire

qs.parse(this.props.location.search, { ignoreQueryPrefix: true }).__firebase_request_key

Une autre bibliothèque serait une chaîne de requête . Voir cette réponse pour plus d'idées sur l'analyse de la chaîne de recherche. Si vous n'avez pas besoin de compatibilité IE, vous pouvez également utiliser

new URLSearchParams(this.props.location.search).get("__firebase_request_key")

Pour les composants fonctionnels, vous devez remplacer this.props.locationpar le crochet useLocation . Remarque, vous pouvez l'utiliser window.location.search, mais cela ne permettra pas de déclencher le rendu React sur les modifications. Si votre composant (non fonctionnel) n'est pas un enfant direct d'un, Switchvous devez utiliser withRouter pour accéder à l'un des accessoires fournis par le routeur.

Général

Suggestion de nizam.sp à faire

console.log(this.props)

sera utile dans tous les cas.

Christian
la source
3
Il n'est pas nécessaire de changer le routeur de réaction pour cela.
Christian
2
Je ne recommanderais pas d'utiliser en console.dir()raison d'une note d'avertissement ... au moins :)
boldnik
1
Eh bien, c'est juste pour regarder le contenu, une fois. Vous pouvez également simplement mettre un point d'arrêt et évaluer this.props dans le débogueur. De nos jours, même console.log fera le travail (au moins dans Chrome, vous pouvez développer des valeurs imprimées comme ça) - et même console.log n'est rien à utiliser en production.
Christian
1
@Christian J'ai fini par utiliser simplement du javascript. const path = window.location.pathname; me donne l'URL. Je peux ensuite l'analyser comme je le dois. J'ai placé ceci dans l'événement de cycle de vie componentWillMount dans mon composant React.
Sam
5
En react-router-domje devais utiliser withRouterpour faire ce travail!
demonofthemist
188

React Router v4

En utilisant component

<Route path="/users/:id" component={UserPage}/> 

this.props.match.params.id

Le composant est automatiquement rendu avec les accessoires d'itinéraire.


En utilisant render

<Route path="/users/:id" render={(props) => <UserPage {...props} />}/> 

this.props.match.params.id

Les accessoires de route sont passés à la fonction de rendu.

spencer.sm
la source
1
J'ai rencontré un problème similaire lors de l'accès à l' query paramsURL actuelle de mon application dans un composant enfant à l'aide de React Router v4. Si vous recherchez le query params, this.props.location.query dans React Router 4 a été supprimé (en utilisant actuellement la v4.1.1). Voir cette réponse: stackoverflow.com/a/43630848/1508105
Alex Johnson
42
Cela ne répond malheureusement pas à la question car vous ne l'aurez pas forcément /users/?q=...mais vous auriez pu /user?q=.... Vous devez utiliser this.props.location.searchdans React Router v4 et analyser les résultats vous-même comme expliqué dans ma réponse ci-dessous.
nbeuchat
Ceci est la bonne réponse. this.props.location.searchn'existe pas.
NickJ
@NickJ: quelle version de React Router utilisez-vous?
nbeuchat
126

React Router v3

Avec React Router v3, vous pouvez obtenir une chaîne de requête à partir de this.props.location.search(? Qs1 = naisarg & qs2 = parmar). Par exemple, avec let params = queryString.parse(this.props.location.search), donnerait{ qs1 : 'naisarg', qs2 : 'parmar'}

React Router v4

Avec React Router v4, le this.props.location.queryn'existe plus. Vous devez utiliser à la this.props.location.searchplace et analyser les paramètres de requête par vous-même ou en utilisant un package existant tel que query-string.

Exemple

Voici un exemple minimal utilisant React Router v4 et la query-stringbibliothèque.

import { withRouter } from 'react-router-dom';
import queryString from 'query-string';

class ActivateAccount extends Component{
    someFunction(){
        let params = queryString.parse(this.props.location.search)
        ...
    }
    ...
}
export default withRouter(ActivateAccount);

Rationnel

L'équipe rationnelle du React Router pour retirer la querypropriété est:

Il existe un certain nombre de packages populaires qui effectuent une analyse / chaîne de chaîne de requête légèrement différemment, et chacune de ces différences peut être la manière "correcte" pour certains utilisateurs et "incorrecte" pour d'autres. Si React Router choisissait le "bon", ce ne serait bon que pour certaines personnes. Ensuite, il faudrait ajouter un moyen pour les autres utilisateurs de se substituer à leur package d'analyse de requête préféré. Il n'y a aucune utilisation interne de la chaîne de recherche par React Router qui l'oblige à analyser les paires clé-valeur, il n'a donc pas besoin de choisir laquelle d'entre elles devrait être "correcte".

[...]

L'approche adoptée pour 4.0 est de supprimer toutes les fonctionnalités «batteries incluses» et de revenir au routage de base. Si vous avez besoin d'une analyse de chaîne de requête ou d'un chargement asynchrone ou d'une intégration Redux ou autre chose très spécifique, vous pouvez l'ajouter avec une bibliothèque spécifiquement pour votre cas d'utilisation. Moins de cruches sont emballées en ce que vous n'avez pas besoin et vous pouvez personnaliser les choses selon vos préférences et vos besoins spécifiques.

Vous pouvez trouver la discussion complète sur GitHub .

nbeuchat
la source
1
Marche parfaitement. Cela devrait être la réponse acceptée à partir de l'été 2018.
mmla
4
pourquoi avez-vous même besoin d'une bibliothèque quand vous pouvez utiliser URLSearchParams
SuperUberDuper
3
@SuperUberDuper à cause de Edge et iOS Safari - developer.mozilla.org/en-US/docs/Web/API/…
Brian Burns
3
Bien sûr, mais utilisez simplement le polyfill URLSearchParams
Anthony Manning-Franklin
67

Pour autant que je sache, il existe trois méthodes pour cela.

1. utilisez l'expression régulière pour obtenir la chaîne de requête.

2. vous pouvez utiliser l'API du navigateur. l'image l'url actuelle est comme ceci:

http://www.google.com.au?token=123

nous voulons juste obtenir 123;

Première

 const query = new URLSearchParams(this.props.location.search);

alors

const token = query.get('token')
console.log(token)//123

3. utilisez une troisième bibliothèque appelée «chaîne de requête». Installez-le d'abord

npm i query-string

Ensuite, importez-le dans le fichier javascript actuel:

 import queryString from 'query-string'

L'étape suivante consiste à obtenir «token» dans l'url actuelle, procédez comme suit:

const value=queryString.parse(this.props.location.search);
const token=value.token;
console.log('token',token)//123

J'espère que cela aide.

Mis à jour le 25/02/2019

  1. si l'URL actuelle ressemble à ceci:

http://www.google.com.au?app=home&act=article&aid=160990

nous définissons une fonction pour obtenir les paramètres:

function getQueryVariable(variable)
{
        var query = window.location.search.substring(1);
        console.log(query)//"app=article&act=news_content&aid=160990"
        var vars = query.split("&");
        console.log(vars) //[ 'app=article', 'act=news_content', 'aid=160990' ]
        for (var i=0;i<vars.length;i++) {
                    var pair = vars[i].split("=");
                    console.log(pair)//[ 'app', 'article' ][ 'act', 'news_content' ][ 'aid', '160990' ] 
        if(pair[0] == variable){return pair[1];}
         }
         return(false);
}

Nous pouvons obtenir de «l'aide» en:

getQueryVariable('aid') //160990
MING WU
la source
URLSearchParams n'est pas pris en charge par IE (si cela est pertinent pour n'importe qui :)
Christian
@Christian Typique IE
Trevor Wood
66

React Router v4 n'a plus l' props.location.query objet (voir la discussion sur github ). La réponse acceptée ne fonctionnera donc pas pour les nouveaux projets.

Une solution pour v4 consiste à utiliser une chaîne de requête de bibliothèque externe pour analyserprops.location.search

const qs = require('query-string');
//or
import * as qs from 'query-string';

console.log(location.search);
//=> '?foo=bar'

const parsed = qs.parse(location.search);
console.log(parsed);
//=> {foo: 'bar'}
JTG
la source
1
Pour une raison quelconque, qs.parse se traduit par:{'?foo': 'bar'}
Chris
2
@Chris var prefixed = qs.parse('?a=b&c=d', { ignoreQueryPrefix: true });devrait le réparer. Exemple trouvé ici: github.com/ljharb/qs
Alan Schapira
38

Lors de l'utilisation de hooks React, il n'y a aucun accès auquel accéder this.props.location. Pour capturer les paramètres d'URL, utilisez windowobject.

const search = window.location.search;
const params = new URLSearchParams(search);
const foo = params.get('bar');
t-reksio
la source
1
Ceci est une merveilleuse réponse. Je vous remercie.
LukeVenter
Vous pouvez utiliser "useLocation" de "react-router-dom" au lieu de l'objet window pour obtenir les mêmes résultats.
Chasmatu
1
URLSearchParams n'est pas pris en charge par IE developer.mozilla.org/en-US/docs/Web/API/URLSearchParams/…
Michael Freidgeim
De plus, l'accès à window.location ne permettra pas de déclencher un nouveau rendu de React sur les modifications.
Christian
25

React Router v4

const urlParams = new URLSearchParams(this.props.location.search)
const key = urlParams.get('__firebase_request_key')

Veuillez noter qu'il est actuellement expérimental.

Vérifiez la compatibilité du navigateur ici: https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams/URLSearchParams#Browser_compatibility

Mike Frenil L
la source
2
Belle solution mais malheureusement IE ne prend pas en charge ((
Andrey Patseiko
@AndreyPatseiko il y a un polyfill pour cela github.com/WebReflection/url-search-params
Earlee
23

vous pouvez vérifier le react-router , en simple, vous pouvez utiliser le code pour obtenir le paramètre de requête tant que vous avez défini dans votre routeur:

this.props.params.userId
TommyLike
la source
25
Ce n'est pas la bonne réponse dans le cas de l'OP. props.paramsest pour les paramètres d'URL (segment d'url préfixé avec ':' dans le routeur de réaction), props.location.querystocke les paramètres de chaîne de requête (après le '?') et est ce que OP veut.
Matthieu Harlé
21

React Router 5.1+

5.1 a introduit divers crochets comme useLocationet useParamsqui pourraient être utiles ici.

Exemple:

<Route path="/test/:slug" component={Dashboard} />

Ensuite, si nous avons visité dire

http://localhost:3000/test/signin?_k=v9ifuf&__firebase_request_key=blablabla

Vous pouvez le récupérer comme

import { useLocation } from 'react-router';
import queryString from 'query-string';

const Dashboard: React.FC = React.memo((props) => {
    const location = useLocation();

    console.log(queryString.parse(location.search));

    // {__firebase_request_key: "blablabla", _k: "v9ifuf"}

    ...

    return <p>Example</p>;
}
dsgriffin
la source
17

Si votre routeur est comme ça

<Route exact path="/category/:id" component={ProductList}/>

Vous obtiendrez cet identifiant comme ceci

this.props.match.params.id
Milan Panigrahi
la source
Quelqu'un sait-il comment cela fonctionne dans React Router 5.0.1? this.props.match.params est toujours vide.
Mark A. Tagliaferro
2
@ MarkA.Tagliaferro L'hélice n'est disponible que pour les composants rendus par une route. Si ce n'est pas le cas pour votre composant, vous pouvez y accéder en encapsulant votre composant dans withRouter HOC.
Jimmy Longley
14

Avec cette doublure, vous pouvez l'utiliser n'importe où dans React Hook et React Class Component avec du JavaScript simple.

https://www.hunterisgod.com/?city=Leipzig

let city = (new URLSearchParams(window.location.search)).get("city")
chasseur
la source
11

Si vous n'obtenez pas le this.props... que vous attendiez sur la base des autres réponses, vous devrez peut-être utiliser withRouter( docs v4 ):

import React from 'react'
import PropTypes from 'prop-types'
import { withRouter } from 'react-router'

// A simple component that shows the pathname of the current location
class ShowTheLocation extends React.Component {
  static propTypes = {
    match: PropTypes.object.isRequired,
    location: PropTypes.object.isRequired,
    history: PropTypes.object.isRequired
  }

  render() {
    const { match, location, history } = this.props

    return (
      <div>You are now at {location.pathname}</div>
    )
  }
}

// Create a new component that is "connected" (to borrow redux terminology) to the router.  
const TwitterSsoButton = withRouter(ShowTheLocation)  

// This gets around shouldComponentUpdate
withRouter(connect(...)(MyComponent))

// This does not
connect(...)(withRouter(MyComponent))
jtlindsey
la source
8

J'ai eu du mal à résoudre ce problème. Si aucun des éléments ci-dessus ne fonctionne, essayez-le à la place. J'utilise l'application create-react-app

Exigences

react-router-dom ":" ^ 4.3.1 "

Solution

À l'emplacement où le routeur est spécifié

<Route path="some/path" ..../>

Ajoutez le nom du paramètre que vous souhaitez transmettre comme ceci

<Route path="some/path/:id" .../>

Sur la page où vous effectuez le rendu / path, vous pouvez le spécifier pour afficher l'ID d'appel du nom du paramètre comme ceci

componentDidMount(){
  console.log(this.props);
  console.log(this.props.match.params.id);
}

À la fin où vous exportez par défaut

export default withRouter(Component);

N'oubliez pas d'inclure l'importation

import { withRouter } from 'react-router-dom'

Lorsque console.log (this.props) vous pourrez ce qui a été transmis. S'amuser!

NarDd
la source
2
Et si vous utilisez TypeScript, n'oubliez pas d'ajouterRouteComponentProps<{id: number}>
ThunderDev
1
où ajoutez-vous RouteComponentProps <{id: number}> ??
Choco
type Props = RouteComponentProps <{id: number}>;
pfeds
classe MyClass étend React.PureComponent <Props> {
pfeds
Ensuite, dans componentDidMount (par exemple), const myId = this.props.match.params.id;
pfeds
7

React routerà partir de la v4 ne vous donne plus query paramsdirectement le dans son locationobjet. La raison étant

Il existe un certain nombre de packages populaires qui effectuent une analyse / chaîne de chaîne de requête légèrement différemment, et chacune de ces différences peut être la manière "correcte" pour certains utilisateurs et "incorrecte" pour d'autres. Si React Router choisissait le "bon", ce ne serait bon que pour certaines personnes. Ensuite, il faudrait ajouter un moyen pour les autres utilisateurs de se substituer à leur package d'analyse de requête préféré. Il n'y a aucune utilisation interne de la chaîne de recherche par React Router qui l'oblige à analyser les paires clé-valeur, il n'a donc pas besoin de choisir laquelle d'entre elles devrait être "correcte".

Cela étant, il serait plus logique d'analyser simplement location.search dans vos composants de vue qui attendent un objet de requête.

Vous pouvez le faire génériquement en redéfinissant la withRouterde react-routercomme

customWithRouter.js

import { compose, withPropsOnChange } from 'recompose';
import { withRouter } from 'react-router';
import queryString from 'query-string';

const propsWithQuery = withPropsOnChange(
    ['location', 'match'],
    ({ location, match }) => {
        return {
            location: {
                ...location,
                query: queryString.parse(location.search)
            },
            match
        };
    }
);

export default compose(withRouter, propsWithQuery)
Shubham Khatri
la source
6
componentDidMount(){
    //http://localhost:3000/service/anas
    //<Route path="/service/:serviceName" component={Service} />
    const {params} =this.props.match;
    this.setState({ 
        title: params.serviceName ,
        content: data.Content
    })
}
Anas Alpure
la source
4
Bienvenue dans Stack Overflow! Veuillez ne pas répondre uniquement avec le code source. Essayez de fournir une belle description du fonctionnement de votre solution. Voir: Comment écrire une bonne réponse? . Merci
sɐunıɔ ןɐ qɐp
1
Va probablement obtenir une «donnée» n'est pas définie non-undef
Tom Stickel
6

Peut-être un peu en retard mais ce crochet réactif peut vous aider à obtenir / définir des valeurs dans la requête URL: https://github.com/rudyhuynh/use-url-search-params (écrit par moi).

Cela fonctionne avec ou sans react-router. Voici un exemple de code dans votre cas:

import React from "react";
import { useUrlSearchParams } from "use-url-search-params";

const MyComponent = () => {
  const [params, setParams] = useUrlSearchParams()
  return (
    <div>
      __firebase_request_key: {params.__firebase_request_key}
    </div>
  )
}
Ruby Ybur
la source
Merci beaucoup d'avoir fourni un crochet aussi simple mais génial!
chr1s
5

this.props.params.your_param_name marchera.

C'est le moyen d'obtenir les paramètres de votre chaîne de requête.
Veuillez faire console.log(this.props);pour explorer toutes les possibilités.

nizam.sp
la source
3

Dans le composant où vous devez accéder aux paramètres que vous pouvez utiliser

this.props.location.state.from.search

qui révèlera toute la chaîne de requête (tout ce qui se trouve après le ?signe)

Rocco Ghielmini
la source
2

Dans React Router v4 uniquement avecRoute est la manière correcte

Vous pouvez accéder aux propriétés de l'objet historique et à la correspondance la plus proche via le composant d'ordre supérieur withRouter. withRouter transmettra les accessoires de correspondance, l'emplacement et l'historique mis à jour au composant encapsulé à chaque rendu.

import React from 'react'
import PropTypes from 'prop-types'
import { withRouter } from 'react-router'

// A simple component that shows the pathname of the current location
class ShowTheLocation extends React.Component {
  static propTypes = {
    match: PropTypes.object.isRequired,
    location: PropTypes.object.isRequired,
    history: PropTypes.object.isRequired
  }

  render() {
    const { match, location, history } = this.props

    return (
      <div>You are now at {location.pathname}</div>
    )
  }
}

// Create a new component that is "connected" (to borrow redux
// terminology) to the router.
const ShowTheLocationWithRouter = withRouter(ShowTheLocation)

https://reacttraining.com/react-router/web/api/withRouter

krystianj
la source
2

J'ai utilisé un package externe appelé chaîne de requête pour analyser le paramètre URL comme ceci.

import React, {Component} from 'react'
import { parse } from 'query-string';

resetPass() {
    const {password} = this.state;
    this.setState({fetching: true, error: undefined});
    const query = parse(location.search);
    return fetch(settings.urls.update_password, {
        method: 'POST',
        headers: {'Content-Type': 'application/json', 'Authorization': query.token},
        mode: 'cors',
        body: JSON.stringify({password})
    })
        .then(response=>response.json())
        .then(json=>{
            if (json.error)
                throw Error(json.error.message || 'Unknown fetch error');
            this.setState({fetching: false, error: undefined, changePassword: true});
        })
        .catch(error=>this.setState({fetching: false, error: error.message}));
}
Joe
la source
2

Lorsque vous travaillez avec react route dom, alors videz l'objet avec for match, mais si vous faites le code suivant, il sera utilisé pour le composant es6 ainsi que pour le composant function.

import { Switch, Route, Link } from "react-router-dom";

<Route path="/profile" exact component={SelectProfile} />
<Route
  path="/profile/:profileId"
  render={props => {
    return <Profile {...props} loading={this.state.loading} />;
  }}
/>
</Switch>
</div>

De cette façon, vous pouvez obtenir des accessoires et faire correspondre les paramètres et l'ID de profil

Cela a fonctionné pour moi après de nombreuses recherches sur le composant es6.

Jayant Patil
la source
1

Ou peut-être quelque chose comme ça?

let win = {
  'location': {
    'path': 'http://localhost:8000/#/signin?_k=v9ifuf&__firebase_request_key=blablabla'
  }
}
if (win.location.path.match('__firebase_request_key').length) {
  let key = win.location.path.split('__firebase_request_key=')[1]
  console.log(key)
}

prabhu
la source
0

Vous pouvez créer un crochet simple pour extraire les paramètres de recherche de l'emplacement actuel:

import React from 'react';
import { useLocation } from 'react-router-dom';

export function useSearchParams<ParamNames extends string[]>(...parameterNames: ParamNames): Record<ParamNames[number], string | null> {
    const { search } = useLocation();
    return React.useMemo(() => { // recalculate only when 'search' or arguments changed
        const searchParams = new URLSearchParams(search);
        return parameterNames.reduce((accumulator, parameterName: ParamNames[number]) => {
            accumulator[ parameterName ] = searchParams.get(parameterName);
            return accumulator;
        }, {} as Record<ParamNames[number], string | null>);
    }, [ search, parameterNames.join(',') ]); // join for sake of reducing array of strings to simple, comparable string
}

alors vous pouvez l'utiliser dans votre composant fonctionnel comme ceci:

// current url: http://localhost:8000/#/signin?_k=v9ifuf&__firebase_request_key=blablabla
const { __firebase_request_key } = useSearchParams('__firebase_request_key');
// current url: http://localhost:3000/home?b=value
const searchParams = useSearchParameters('a', 'b'); // {a: null, b: 'value'}
kajkal
la source
-2
export class ClassName extends Component{
      constructor(props){
        super(props);
        this.state = {
          id:parseInt(props.match.params.id,10)
        }
    }
     render(){
        return(
          //Code
          {this.state.id}
        );
}
Roushan Jha
la source
-3
let data = new FormData();
data.append('file', values.file);
Fatemeh kazemi zadeh virus3000
la source
-5

la solution la plus simple!

en routage:

   <Route path="/app/someUrl/:id" exact component={binder} />

dans le code react:

componentDidMount() {
    var id = window.location.href.split('/')[window.location.href.split('/').length - 1];
    var queryString = "http://url/api/controller/" + id
    $.getJSON(queryString)
      .then(res => {
        this.setState({ data: res });
      });
  }
UN J
la source