React - jak uzyskać wartość parametru z ciągu zapytania

412

Jak mogę zdefiniować trasę w pliku tras.jsx w celu przechwycenia __firebase_request_keywartości parametru z adresu URL wygenerowanego przez proces pojedynczego logowania Twittera po przekierowaniu z ich serwerów?

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

Próbowałem z następującą konfiguracją tras, ale :redirectParamnie łapie wspomnianego parametru:

<Router>
  <Route path="/" component={Main}>
    <Route path="signin" component={SignIn}>
      <Route path=":redirectParam" component={TwitterSsoButton} />
    </Route>
  </Route>
</Router>
Franco
źródło
1
Istnieje dyskusja Github tutaj
vsync
3
niefortunne, że pytanie mówi „ciągi zapytania”, ale w rzeczywistości pyta o „parametry
adresu
6
query strings„? var1 = val & var2 = val2”,: „ url paramters/ photos /: companyiD / new”
Maddocks

Odpowiedzi:

484

React Router v3

React Router już analizuje lokalizację dla Ciebie i przekazuje ją do RouteComponent jako rekwizyty. Możesz uzyskać dostęp do części zapytania (po? W adresie URL) za pośrednictwem

this.props.location.query.__firebase_request_key

Jeśli szukasz wartości parametrów ścieżki oddzielonych dwukropkiem (:) wewnątrz routera, są one dostępne poprzez

this.props.match.params.redirectParam

Dotyczy to późnych wersji React Router v3 (nie jestem pewien, które). Zgłoszono, że używają starszych wersji routerów this.props.params.redirectParam.

React Router v4 i React Router v5, ogólne

React Router v4 nie analizuje już zapytania, ale można uzyskać do niego dostęp tylko poprzez this.props.location.search. Z przyczyn zobacz odpowiedź nbeuchat .

Np qs biblioteki importowanego jak qsmożna zrobić

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

Inną biblioteką byłby ciąg zapytania . Zobacz tę odpowiedź, aby uzyskać więcej pomysłów na analizowanie ciągu wyszukiwania. Jeśli nie potrzebujesz kompatybilności z IE , możesz także użyć

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

W przypadku komponentów funkcjonalnych należy zastąpić this.props.locationhakiem useLocation . Uwaga, możesz użyć window.location.search, ale nie pozwoli to na uruchomienie React renderingu na zmiany. Jeśli twój (niefunkcjonalny) komponent nie jest bezpośrednim dzieckiem Switch, musisz użyć go z routerem aby uzyskać dostęp do dowolnego z podanych routerów.

Generał

Sugestia nizam.sp

console.log(this.props)

w każdym razie będzie pomocny.

chrześcijanin
źródło
3
Zmiana routera reagującego nie jest wymagana.
Christian
2
Nie sugerowałbym używania console.dir()ze względu na ostrzeżenie ... przynajmniej :)
boldnik
1
Cóż, to tylko raz, żeby spojrzeć na zawartość. Możesz także po prostu ustawić punkt przerwania i ocenić to .props w debuggerze. Obecnie nawet konsola.log wykona zadanie (przynajmniej w Chrome możesz rozszerzyć tak wydrukowane wartości) - a nawet konsola.log nie ma nic do zastosowania w produkcji.
Christian
1
@Christian Skończyło się na zwykłym javascript. const path = window.location.pathname; daje mi adres URL. Następnie mogę go przeanalizować w odpowiedni sposób. Umieściłem to w zdarzeniu cyklu życia componentWillMount w moim komponencie React.
Sam
5
W react-router-domMusiałem użyć, withRouteraby to zadziałało!
demonofthemist,
188

React Router v4

Za pomocą component

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

this.props.match.params.id

Komponent jest automatycznie renderowany za pomocą rekwizytów trasy.


Za pomocą render

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

this.props.match.params.id

Rekwizyty trasy są przekazywane do funkcji renderowania.

spencer.sm
źródło
1
Miałem podobny problem z dostępem do query paramsbieżącego adresu URL mojej aplikacji w komponencie potomnym za pomocą React Router v4. Jeśli szukasz query params, to.props.location.query w React Router 4 został usunięty (obecnie używa wersji 4.1.1). Zobacz tę odpowiedź: stackoverflow.com/a/43630848/1508105
Alex Johnson
41
To niestety nie odpowiada na pytanie, ponieważ niekoniecznie /users/?q=...będziesz musiał, ale możesz /user?q=.... Powinieneś użyć this.props.location.searchw React Router v4 i sam przeanalizować wyniki, jak wyjaśniono w mojej odpowiedzi poniżej.
nbeuchat
To jest poprawna odpowiedź. this.props.location.searchnie istnieje.
NickJ
@NickJ: jakiej wersji React Router używasz?
nbeuchat
126

React Router v3

Za pomocą React Router v3 możesz uzyskać ciąg zapytania od this.props.location.search(? Qs1 = naisarg & qs2 = parmar). Na przykład z let params = queryString.parse(this.props.location.search), dałoby{ qs1 : 'naisarg', qs2 : 'parmar'}

React Router v4

Z React Router v4 this.props.location.queryjuż nie istnieje. Zamiast tego musisz użyć this.props.location.searchi przeanalizować parametry zapytania samodzielnie lub przy użyciu istniejącego pakietu, takiego jak query-string.

Przykład

Oto minimalny przykład użycia React Router v4 i query-stringbiblioteki.

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);

Racjonalny

Zespół React Router racjonalnie usuwa tę querywłaściwość:

Istnieje wiele popularnych pakietów, które nieco inaczej przetwarzają kwerendy / łańcuchy zapytań, a każda z tych różnic może być „poprawna” dla niektórych użytkowników i „niepoprawna” dla innych. Gdyby React Router wybrał „właściwy”, byłby odpowiedni tylko dla niektórych osób. Następnie należałoby dodać sposób, w jaki inni użytkownicy mogą zastępować w preferowanym pakiecie parsowania zapytań. React Router nie używa wewnętrznego ciągu wyszukiwania, który wymaga analizowania par klucz-wartość, więc nie ma potrzeby wybierania, która z nich powinna być „właściwa”.

[...]

Podejście przyjęte w przypadku wersji 4.0 polega na usunięciu wszystkich „dołączonych baterii” funkcji i przywróceniu tylko podstawowego routingu. Jeśli potrzebujesz parsowania ciągów zapytań, ładowania asynchronicznego lub integracji Redux lub czegoś innego bardzo specyficznego, możesz to dodać w bibliotece specjalnie dla twojego przypadku użycia. Mniej cruft jest pakowany w to, czego nie potrzebujesz i możesz dostosować rzeczy do swoich konkretnych preferencji i potrzeb.

Pełną dyskusję można znaleźć na GitHub .

nbeuchat
źródło
1
Działa świetnie. To powinna być zaakceptowana odpowiedź na lato 2018 r.
mmla
4
dlaczego potrzebujesz biblioteki lib, kiedy możesz używać URLSearchParams
SuperUberDuper
3
@SuperUberDuper z powodu przeglądarki Edge i iOS Safari - developer.mozilla.org/en-US/docs/Web/API/…
Brian Burns
3
Jasne, ale wystarczy użyć wypełnienia URLSearchParams
Anthony Manning-Franklin
67

O ile mi wiadomo, istnieją trzy metody, aby to zrobić.

1. użyj wyrażenia regularnego, aby uzyskać ciąg zapytania.

2. możesz użyć interfejsu API przeglądarki. obraz aktualny adres URL wygląda następująco:

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

chcemy tylko dostać 123;

Pierwszy

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

Następnie

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

3. użyj trzeciej biblioteki o nazwie „ciąg zapytania”. Najpierw zainstaluj

npm i query-string

Następnie zaimportuj go do bieżącego pliku javascript:

 import queryString from 'query-string'

Następnym krokiem jest uzyskanie „tokena” w bieżącym adresie URL, wykonaj następujące czynności:

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

Mam nadzieję, że to pomoże.

Zaktualizowano 25.02.2019

  1. jeśli bieżący adres URL wygląda następująco:

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

definiujemy funkcję, aby uzyskać parametry:

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);
}

Możemy uzyskać „pomoc” poprzez:

getQueryVariable('aid') //160990
MING WU
źródło
URLSearchParams nie jest obsługiwany przez IE (jeśli dotyczy to każdego :)
Christian
@Christian Typical IE
Trevor Wood
66

React Router v4 nie ma już props.location.query obiektu (patrz github dyskusja na ). Tak więc zaakceptowana odpowiedź nie będzie działać w przypadku nowszych projektów.

Rozwiązaniem dla v4 jest użycie zewnętrznego łańcucha zapytania biblioteki do parsowaniaprops.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
źródło
1
Z jakiegoś powodu qs.parse powoduje:{'?foo': 'bar'}
Chris
2
@Chris var prefixed = qs.parse('?a=b&c=d', { ignoreQueryPrefix: true });powinien to naprawić. Przykład znaleziony tutaj: github.com/ljharb/qs
Alan Schapira
38

Podczas korzystania z haków React nie ma dostępu do dostępu this.props.location. Aby przechwycić parametry adresu URL, użyj windowobiektu.

const search = window.location.search;
const params = new URLSearchParams(search);
const foo = params.get('bar');
t-reksio
źródło
1
To wspaniała odpowiedź. Dziękuję Ci.
LukeVenter,
Możesz użyć „useLocation” z „React-router-dom” zamiast obiektu okna, aby osiągnąć te same wyniki.
Chasmatu
1
URLSearchParams nie jest obsługiwany przez IE developer.mozilla.org/en-US/docs/Web/API/URLSearchParams/…
Michael Freidgeim
Ponadto dostęp do window.location nie pozwoli na ponowne renderowanie Reacta po zmianach.
Christian
25

React Router v4

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

Uwaga: obecnie jest w fazie eksperymentalnej.

Sprawdź kompatybilność przeglądarki tutaj: https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams/URLSearchParams#Browser_compatibility

Mike Frenil L.
źródło
2
Ładne rozwiązanie, ale niestety IE nie obsługuje ((
Andrey Patseiko
@AndreyPatseiko istnieje polifill dla tego github.com/WebReflection/url-search-params
Earlee
23

możesz sprawdzić router reagujący , w prosty sposób możesz użyć kodu, aby uzyskać parametr zapytania, o ile zdefiniowano w routerze:

this.props.params.userId
TommyLike
źródło
25
To nie jest właściwa odpowiedź w przypadku PO. props.paramsjest dla parametrów URL (segment adresu URL z prefiksem „:” w routerze reagującym), props.location.queryprzechowuje parametry ciągu zapytania (po „?”) i jest tym, czego chce OP.
Matthieu Harlé,
20

React Router 5.1+

5.1 wprowadził różne haki, takie jak useLocationiuseParams które mogłyby być użyteczne tutaj.

Przykład:

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

Więc jeśli odwiedzimy powiedz

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

Możesz to odzyskać jak

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
źródło
17

Jeśli twój router jest taki

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

Otrzymasz taki identyfikator

this.props.match.params.id
Milan Panigrahi
źródło
Czy ktoś wie, jak to działa w React Router 5.0.1? this.props.match.params jest zawsze pusty.
Mark A. Tagliaferro,
2
@ MarkA.Tagliaferro Rekwizyt jest dostępny tylko dla komponentów renderowanych przez Trasę. Jeśli tak nie jest w przypadku twojego komponentu, możesz uzyskać do nich dostęp poprzez zawinięcie komponentu w withRouter HOC.
Jimmy Longley,
13

Dzięki tej jednowierszowej możesz go używać w dowolnym miejscu zarówno w React Hook, jak i React Class Component z czystym JavaScript.

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

let city = (new URLSearchParams(window.location.search)).get("city")
Łowca
źródło
11

Jeśli nie otrzymujesz this.props... oczekiwanych na podstawie innych odpowiedzi, być może będziesz musiał użyć 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
źródło
8

Trudno mi było rozwiązać ten problem. Jeśli żadna z powyższych czynności nie działa, możesz zamiast tego spróbować. Korzystam z aplikacji create-reag-app

Wymagania

reag-router-dom ":" ^ 4.3.1 "

Rozwiązanie

W miejscu, w którym określono router

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

Dodaj nazwę parametru, który chcesz przekazać w ten sposób

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

Na stronie, na której renderujesz część / path, możesz to określić, aby wyświetlić identyfikator wywołania nazwy parametru w ten sposób

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

Na końcu, gdzie eksportujesz domyślne

export default withRouter(Component);

Pamiętaj, aby dołączyć import

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

Gdy console.log (this.props) będziesz w stanie, co zostało przekazane. Baw się dobrze!

NarDd
źródło
2
A jeśli używasz TypeScript, nie zapomnij dodaćRouteComponentProps<{id: number}>
ThunderDev
1
gdzie dodajesz RouteComponentProps <{id: number}> ??
Choco
typ Props = RouteComponentProps <{id: number}>;
pfeds
klasa MyClass rozszerza React.PureComponent <Props> {
pfeds
Następnie w componentDidMount (na przykład) const myId = this.props.match.params.id;
pfeds
7

React routerod wersji 4 nie daje już query paramsbezpośrednio w swoim locationobiekcie. Powodem jest

Istnieje wiele popularnych pakietów, które nieco inaczej przetwarzają kwerendy / pisząc łańcuch, a każda z tych różnic może być „poprawna” dla niektórych użytkowników i „niepoprawna” dla innych. Gdyby React Router wybrał „właściwy”, byłby odpowiedni tylko dla niektórych osób. Następnie należałoby dodać sposób, w jaki inni użytkownicy mogą zastępować w preferowanym pakiecie parsowania zapytań. React Router nie używa wewnętrznego ciągu wyszukiwania, który wymaga analizowania par klucz-wartość, więc nie ma potrzeby wybierania, która z nich powinna być „właściwa”.

Po uwzględnieniu tego, sensowniejsze byłoby po prostu przeanalizowanie lokalizacji. Szukaj w widoku komponentów, które oczekują obiektu zapytania.

Można to zrobić poprzez nadpisanie rodzajowo withRouterz react-routerniczym

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
źródło
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
źródło
4
Witamy w Stack Overflow! Proszę nie odpowiadać tylko kodem źródłowym. Spróbuj podać ładny opis działania twojego rozwiązania. Zobacz: Jak napisać dobrą odpowiedź? . Dzięki
sɐunıɔ ןɐ qɐp
1
Prawdopodobnie uzyskanie „danych” nie jest zdefiniowane bez undef
Tom Stickel
6

Może trochę późno, ale ten haczyk na reakcję może pomóc ci uzyskać / ustawić wartości w zapytaniu URL: https://github.com/rudyhuynh/use-url-search-params (napisane przeze mnie).

Działa z lub bez react-router. Poniżej znajduje się przykładowy kod w twoim przypadku:

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
źródło
Dziękuję bardzo za zapewnienie tak prostego, ale świetnego haka!
chr1s
5

this.props.params.your_param_name będzie działać.

Jest to sposób na uzyskanie parametrów z ciągu zapytania.
Proszę zrobić, console.log(this.props);aby zbadać wszystkie możliwości.

nizam.sp
źródło
3

W komponencie, w którym musisz uzyskać dostęp do parametrów, których możesz użyć

this.props.location.state.from.search

który ujawni cały ciąg zapytania (wszystko po ?znaku)

Rocco Ghielmini
źródło
2

W React Router v4 tylko zRoute jest prawidłowym sposobem

Możesz uzyskać dostęp do właściwości obiektu historii i najbliższego dopasowania za pomocą komponentu wyższego rzędu withRouter. withRouter przekaże zaktualizowane rekwizyty dopasowania, lokalizacji i historii do opakowanego komponentu za każdym razem, gdy jest renderowany.

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
źródło
2

Użyłem zewnętrznego pakietu o nazwie ciąg-zapytania do parsowania parametru adresu URL w ten sposób.

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
źródło
2

Kiedy pracujesz z reakcją dom trasy, wówczas opróżnisz obiekt w celu dopasowania, ale jeśli wykonasz następujący kod, będzie to działało dla komponentu es6, a także działa bezpośrednio dla komponentu funkcji

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>

W ten sposób możesz uzyskać rekwizyty i dopasować parametry i identyfikator profilu

To zadziałało dla mnie po wielu badaniach dotyczących komponentu es6.

Jayant Patil
źródło
1

A może coś takiego?

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
źródło
0

Możesz utworzyć prosty hak do wyodrębniania parametrów wyszukiwania z bieżącej lokalizacji:

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
}

możesz użyć go w swoim funkcjonalnym komponencie w następujący sposób:

// 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
źródło
-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
źródło
-3
let data = new FormData();
data.append('file', values.file);
fatemeh kazemi zadeh virus3000
źródło
-5

najprostsze rozwiązanie!

w routingu:

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

w reagującym kodzie:

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 });
      });
  }
AJ
źródło