How to reuse a const object between pages in React? - javascript

I'm using this snippet below to translate my website content. However, there's a way to avoid copying and pasting this code between pages?
import SampleSection from "../section/sample"
import { useRouter } from 'next/router'
import en from '../locales/en'
import pt from '../locales/pt'
export default function Home() {
const router = useRouter()
const { locale } = router
const t = locale === 'en' ? en : pt
const changeLanguage = (e) => {
const locale = e.target.value;
router.push({ pathname, query }, asPath, { locale: locale })
}
return (
<>
<SampleSection
title={t.home.title}
/>
</>
)
}

This is a good opportunity to create your own hook. Basically just extract that logic that you'd need to re-use, stick it in a function and export it. Then you can call it as a hook in as many components as you need to.
More information about creating your own hooks can be found here https://reactjs.org/docs/hooks-custom.html.

Complementing what Justin Formentin said, you'll need to name the hook as useABC where ABC is the name you wanna use.

Related

Router.push is returning my objects as undefined, the array length is correct but the value is "" in Next.js [duplicate]

I got a problem with my dynamic route. It look like this
[lang]/abc
I am trying to get query value from [lang] but when I using useRouter/withRouter i got query during 2-3 render of page ( on first i got query.lang = undefined ). its possible to get in 1 render or use any technique ?
I found something:
isReady: boolean - Whether the router fields are updated client-side and ready for use. Should only be used inside of useEffect methods and not for conditionally rendering on the server.
https://nextjs.org/docs/api-reference/next/router#router-object
And the code would be like:
const router = useRouter();
useEffect(()=>{
if(!router.isReady) return;
// codes using router.query
}, [router.isReady]);
It's impossible to get the query value during the initial render.
Statically optimized pages are hydrated without the route parameters, so the query is an empty object ({}).
Next.js will populate the query after the page has been hydrated.
Next.js 10.0.5 and up
To determine if the route params are ready, you can use router.isReady inside a useEffect hook. For an example, see the answer provided by #doxylee.
Before Next.js 10.0.5
At first render of a dynamic route router.asPath and router.route are equal. Once query object is available, router.asPath reflects it.
You can rely on the query value within a useEffect hook after asPath has been changed.
const router = useRouter();
useEffect(() => {
if (router.asPath !== router.route) {
// router.query.lang is defined
}
}, [router])
GitHub Issue - Add a "ready" to Router returned by "useRouter"
In NextJS 9+, one way to ensure route parameters are immediately available for page components is to get them from the context arg passed to getServerSideProps() and pass to the component as props.
For a page like [id].js,
export function getServerSideProps(context) {
return {
props: {params: context.params}
};
}
export default ({params}) => {
const {id} = params;
return <div>You opened page with {id}</div>;
};
This is a great question and one that took a few days for me to figure out what the best approach is.
I have personally found three viable solutions to the problem of validating dynamic route path params or even just route path params in general.
The three solutions are
SSR (don't recommend) [Next >= 10]
useRouter
Middleware [Next 12 required]
In my examples a will use a route that requires a reset-token or it should be redirected.
SSR
Firstly server side rending with getServerSideProps.
Vercel recommends to use SSR as a last resort and I would highly recommend not using SSR when able (time to byte & cost).
We suggest trying Incremental Static Generation or Client-side Fetching and see if they fit your needs.
https://vercel.com/blog/nextjs-server-side-rendering-vs-static-generation
But in the case that you do, say there is some server side api validation call you require to validate the query param.
export const getServerSideProps = async (context) => {
const { token } = context.query;
if (!token) {
return {
redirect: {
permanent: false,
destination: "/",
}
}
}
return {
props: {}
// props: { token }
// You could do this either with useRouter or passing props
}
}
useRouter Secondly the easiest useRouter. When I first did this I came across the problem when nextjs/react hydrates there will be a point when the query params are null. Luckily useRouter has isReady!
import Router, { useRouter } from "next/router";
const { query, isReady } = useRouter();
useEffect(() => {
if (!isReady) return;
if (!query.token) {
Router.push("/")
}
}, [isReady])
Middleware now this is my personal favourite as it seperates the functionality in a clean way imo.
I found this based of a vercel example. I would highly recommend reading through a bunch of these to find best practices.
https://github.com/vercel/examples/
import { NextResponse, NextRequest } from 'next/server'
export async function middleware(req) {
const { pathname, searchParams } = req.nextUrl
if (pathname == '/reset-token') {
const index = searchParams.findIndex(x => x.key === "token")
// You could also add token validation here.
if (!index) {
return NextResponse.redirect('/')
}
}
return NextResponse.next()
}
Here is the repo which has some cool filtering of query parameters.
This is a more soft approach instead of hard redirecting.
https://github.com/vercel/examples/tree/main/edge-functions/query-params-filter
Nico also has a great answer on this, expect I wouldn't recommend using hooks like in his example, instead use isReady.
https://stackoverflow.com/a/58182678/4918639
For Class Component Lovers
The even better approach is to listen for a dedicated event for this routeChangeComplete using this.props.router.events.on method, inside componentDidMount if you're using class component -
routeChangeComplete = () => {
// this WILL have valid query data not empty {}
console.log(this.props.router.query);
};
componentDidMount() {
this.props.router.events.on("routeChangeComplete", this.routeChangeComplete);
}
componentWillUnmount() {
this.props.router.events.off("routeChangeComplete", this.routeChangeComplete);
}
Ref: https://nextjs.org/docs/api-reference/next/router#routerevents
routeChangeComplete: Fires when a route changed completely.
Practically when isReady has become true or when router.query object has data.
For NextJS version - 12.0.8
"If you export a function called getServerSideProps (Server-Side Rendering) from a page, Next.js will pre-render this page on each request using the data returned by getServerSideProps."
=async functions
refference:https://nextjs.org/docs/basic-features/data-fetching/get-server-side-props#getserversideprops
Simply putting that async function on the page notifies NextJS of its presence.During prerendering stage of the component, the query object of the router will be empty.
isReady: boolean - Whether the router fields are updated client-side and ready for use. Should only be used inside of useEffect methods and not for conditionally rendering on the server.
refference: https://nextjs.org/docs/api-reference/next/router
solution:
import { useRouter } from 'next/router';
const Fn = () =>{
const router = useRouter();
const { param } = router.query;
const fetchData = async () => {
await fetch();
}
useEffect(() => {
fetchCat();
}, [router.isReady]);
}
I resolved my problem that I need it in Hoc component.
I wrapped using withRouter(withLocale(Comp)) and create conditional in HOC
export default function withLocale(WrappedPage) {
const WithLocale = ({ router, ...props }) => {
const { lang } = router.query;
if (!lang || !isLocale(lang)) {
return <Error statusCode={404} />;
}
return (
<LocaleProvider lang={lang}>
<WrappedPage {...props} />
</LocaleProvider>
);
};
return WithLocale;
}
Next.js <= 10.0.5
This is a good work around, I found around from this comment
Add useQuery.ts helper file
// useQuery.js
import { useRouter } from 'next/router';
// Resolves query or returns null
export default function useQuery() {
const router = useRouter();
const ready = router.asPath !== router.route;
if (!ready) return null;
return router.query;
}
usage
// In your components (instead of useRouter)
const query = useQuery();
useEffect(() => {
if (!query) {
return;
}
console.log('my query exists!!', query);
}, [query]);
Class Component | 12/16/2022 | React JS 18.2.0 | Next JS 13.0.6
I got the answer for those who want to use Class Component. This was actually nowhere to be found ! Enjoy !
You will add if(this.props.router.isReady) and include return in the condition in render().
.
.
import { withRouter } from 'next/router';
import { Component } from 'react';
class User extends Component {
...
render() {
if(this.props.router.isReady){ // Add this condition and include return ()
// Do anything
console.log(this.props.router.query) // Log 'query' on first render
return (
<div>
<SearchBar pid={this.props.router.query.pid} /> // Pass the query params to another component if needed
</div>
);
}
}
}
export default withRouter(User);

How to use "useContext" in typescript?

I am trying to make a dark/light theme system in my project, but I am having some problems with the code.
This line of code works fine in javascript:
const [darktheme, setDarkTheme] = useContext(ThemeContext);
But when I write it into typescript, I get 6 errors.
I know that some of these variables need to have their type declared, but I only know the type of the darkTheme variable, which is a boolean.
After I declare the types, 2 errors go away, but there is still 4 errors!
const [darktheme: boolean, setDarkTheme: any] = useContext(ThemeContext);
I used any after dark theme, which is not good practice but I didn't know the type
Now I just get these errors:
I think that the main problem with my project is that I am trying to integrate javascript with typescript. I don't know if that is normal or not, but I am doing it because some components are much easier to write with typescript, and some more basic components are better written in javascript.
Here is part of my app.js:
// Context
export const ThemeContext = React.createContext();
function App() {
const [darkTheme, setDarkTheme] = useState(false);
return (
<ThemeContext.Provider value={[darkTheme, setDarkTheme]}>
,and when I use the function in this component, it works just fine:
import React, { useContext } from 'react';
import { ThemeContext } from '../App';
import Button from 'react-bootstrap/Button';
export default function DarkThemeTest() {
const [darktheme, setDarkTheme] = useContext(ThemeContext);
return (
<Button onClick={() => {
setDarkTheme(!darktheme);
}}>
Theme: {darktheme && "Dark" || "Light"}
</Button>
)
}
First, define a type for your context value
import { createContext, Dispatch, SetStateAction } from "react";
interface ThemeContextType {
darkTheme: boolean;
// this is the type for state setters
setDarkTheme: Dispatch<SetStateAction<boolean>>;
}
Then, create your context with this type and initialise it with a default value. This might seem unnecessary but it will avoid checking for null or undefined context later on
export const ThemeContext = createContext<ThemeContextType>({
darkTheme: false,
setDarkTheme: () => {}, // no-op default setter
});
Once you have created your state value and setter, set them into the context provider value
<ThemeContext.Provider value={{ darkTheme, setDarkTheme }}>
Now you can destructure the context value easily via useContext with full type support
const { darkTheme, setDarkTheme } = useContext(ThemeContext);
You could continue to use your array format though I wouldn't recommend it.
type ThemeContextType = [boolean, Dispatch<SetStateAction<boolean>>];
export const ThemeContext = createContext<ThemeContextType>([false, () => {}]);
and
<ThemeContext.Provider value={[darkTheme, setDarkTheme]}>

How to get the current full URL in Next.js/Typescript component?

I have a component that I need to get the current full URL in, here's the simplied version:
/**
* Share dropdown component
*/
export const ShareDropdown: React.FC<{ className: string }> = ({
className,
}) => {
return (
<div className={className}>{currentURL}</div>
)
}
Did some Googling and saw some say use Next's router (but didn't see that return the domain), other using getInitialProps but didn't see how to incorporate into a functional component.
New to all of this, so just trying to find the best way, seems like it should be simple.
You can use simply useRouter from nextjs just like this
import { useRouter } from 'next/router';
...
const { asPath } = useRouter();
...
return (
<div className={className}>http://example.com{asPath}</div>
)
Additionally you can save http://example.com in your environment variables
If you have configured a base path you need to get it
import { useRouter, basePath } from 'next/router';
More info about useRouter here
Store window.location.href as a variable. so, like: const URL = window.location.href and then simply put {URL} here:
/**
* Share dropdown component
*/
export const ShareDropdown: React.FC<{ className: string }> = ({
className,
}) => {
const URL = window.location.href
return (
<div className={className}>{URL}</div>
)
}

Custom hook's state does not update across all components?

import { useState } from 'react';
export default function usePrivacyMode() {
const [isPrivacyOn, setIsPrivacyOn] = useState(false);
return {
isPrivacyOn,
setIsPrivacyOn
};
}
This is my custom hook. I set the state in PrivacyIcons component, and then I use isPrivacyOn for show/hide values from a table based on the value. But in a different component the isPrivacyOn is not changed, it's changed only in PrivacyIcons? Why I can't change it in one component and then use the value across all components? Thanks.
states are not meant to be shared across components. You are looking for useContext. This allows you to share a function and a state between components. React has an excellent tutorial on how to do it in the official documentation: https://reactjs.org/docs/hooks-reference.html#usecontext
For your specific example it would look something like this:
Your App.js
import { useState } from 'react';
export const PrivacyContext = createContext([]);
const App = (props) => {
const [isPrivacyOn, setIsPrivacyOn] = useState(false);
return (
<PrivacyContext.Provider value={[isPrivacyOn, setIsPrivacyOn]}>
<ComponentUsingPrivacyContext />
{props.children}
</PrivacyContext.Provider>
);
};
export default App;
Keep in mind that any component that wants access to that context must be a child of PrivacyContext
Any component that wants to use PrivacyContext:
import React, { useContext } from "react";
import {PrivacyContext} from "...your route";
const ComponentUsingPrivacyContext = (props) => {
const [isPrivacyOn, setIsPrivacyOn] = useContext(PageContext);
return (
<button onclick={setIsPrivacyOn}>
Turn Privacy On
</button>
<span>Privacy is: {isPrivacyOn}</span>
);
};
export default ComponentUsingPrivacyContext;

TypeError: Cannot read property 'params' of undefined (Reactjs router ) [duplicate]

How can I define a route in my routes.jsx file to capture the __firebase_request_key parameter value from a URL generated by Twitter's single sign on process after the redirect from their servers?
http://localhost:8000/#/signin?_k=v9ifuf&__firebase_request_key=blablabla
I tried with the following routes configuration, but the :redirectParam is not catching the mentioned param:
<Router>
<Route path="/" component={Main}>
<Route path="signin" component={SignIn}>
<Route path=":redirectParam" component={TwitterSsoButton} />
</Route>
</Route>
</Router>
React Router v6, using hooks
In react-router-dom v6 there's a new hook named useSearchParams. So with
const [searchParams, setSearchParams] = useSearchParams();
searchParams.get("__firebase_request_key")
you will get "blablabla". Note, that searchParams is an instance of URLSearchParams, which also implements an iterator, e.g. for using Object.fromEntries etc.
React Router v4/v5, without hooks, generic
React Router v4 does not parse the query for you any more, but you can only access it via this.props.location.search (or useLocation, see below). For reasons see nbeuchat's answer.
E.g. with qs library imported as qs you could do
qs.parse(this.props.location.search, { ignoreQueryPrefix: true }).__firebase_request_key
Another library would be query-string. See this answer for some more ideas on parsing the search string. If you do not need IE-compatibility you can also use
new URLSearchParams(this.props.location.search).get("__firebase_request_key")
For functional components you would replace this.props.location with the hook useLocation. Note, you could use window.location.search, but this won't allow to trigger React rendering on changes.
If your (non-functional) component is not a direct child of a Switch you need to use withRouter to access any of the router provided props.
React Router v3
React Router already parses the location for you and passes it to your RouteComponent as props. You can access the query (after ? in the url) part via
this.props.location.query.__firebase_request_key
If you are looking for the path parameter values, separated with a colon (:) inside the router, these are accessible via
this.props.match.params.redirectParam
This applies to late React Router v3 versions (not sure which). Older router versions were reported to use this.props.params.redirectParam.
General
nizam.sp's suggestion to do
console.log(this.props)
will be helpful in any case.
React Router v4
Using component
<Route path="/users/:id" component={UserPage}/>
this.props.match.params.id
The component is automatically rendered with the route props.
Using render
<Route path="/users/:id" render={(props) => <UserPage {...props} />}/>
this.props.match.params.id
Route props are passed to the render function.
React Router v3
With React Router v3, you can get query-string from this.props.location.search (?qs1=naisarg&qs2=parmar). For example, with let params = queryString.parse(this.props.location.search), would give { qs1 : 'naisarg', qs2 : 'parmar'}
React Router v4
With React Router v4, the this.props.location.query does not exist anymore. You need to use this.props.location.search instead and parse the query parameters either by yourself or using an existing package such as query-string.
Example
Here is a minimal example using React Router v4 and the query-string library.
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);
Rational
The React Router's team rational for removing the query property is:
There are a number of popular packages that do query string parsing/stringifying slightly differently, and each of these differences might be the "correct" way for some users and "incorrect" for others. If React Router picked the "right" one, it would only be right for some people. Then, it would need to add a way for other users to substitute in their preferred query parsing package. There is no internal use of the search string by React Router that requires it to parse the key-value pairs, so it doesn't have a need to pick which one of these should be "right".
[...]
The approach being taken for 4.0 is to strip out all the "batteries included" kind of features and get back to just basic routing. If you need query string parsing or async loading or Redux integration or something else very specific, then you can add that in with a library specifically for your use case. Less cruft is packed in that you don't need and you can customize things to your specific preferences and needs.
You can find the full discussion on GitHub.
As far as I know there are three methods you can do that.
1.use regular expression to get query string.
2.you can use the browser api.
image the current url is like this:
http://www.google.com.au?token=123
we just want to get 123;
First
const query = new URLSearchParams(this.props.location.search);
Then
const token = query.get('token')
console.log(token)//123
use a third library called 'query-string'.
First install it
npm i query-string
Then import it to the current javascript file:
import queryString from 'query-string'
Next step is to get 'token' in the current url, do the following:
const value=queryString.parse(this.props.location.search);
const token=value.token;
console.log('token',token)//123
Updated on 25/02/2019
4.
if the current url looks like the following:
http://www.google.com.au?app=home&act=article&aid=160990
we define a function to get the parameters:
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);
}
We can get 'aid' by:
getQueryVariable('aid') //160990
React Router v4 no longer has the props.location.query object (see github discussion). So the accepted answer will not work for newer projects.
A solution for v4 is to use an outside library query-string to parse the props.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'}
When using React hooks there is no access to access to this.props.location.
To capture url parameters use window object.
const search = window.location.search;
const params = new URLSearchParams(search);
const foo = params.get('bar');
React Router 5.1+
5.1 introduced various hooks like useLocation and useParams that could be of use here.
Example:
<Route path="/test/:slug" component={Dashboard} />
Then if we visited say
http://localhost:3000/test/signin?_k=v9ifuf&__firebase_request_key=blablabla
You could retrieve it like
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>;
}
With this one-liner, you can use it anywhere in both React Hook and React Class Component with plain JavaScript.
https://www.hunterisgod.com/?city=Leipzig
let city = (new URLSearchParams(window.location.search)).get("city")
React Router v4
const urlParams = new URLSearchParams(this.props.location.search)
const key = urlParams.get('__firebase_request_key')
Please note that it is currently experimental.
Check browser compatibility here: https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams/URLSearchParams#Browser_compatibility
http://localhost:8000/#/signin?id=12345
import React from "react";
import { useLocation } from "react-router-dom";
const MyComponent = () => {
const search = useLocation().search;
const id=new URLSearchParams(search).get("id");
console.log(id);//12345
}
Not the react way, but I believe that this one-line function could help you :)
const getQueryParams = (query = null) => [...(new URLSearchParams(query||window.location.search||"")).entries()].reduce((a,[k,v])=>(a[k]=v,a),{});
or this:
const getQueryParams = (query = null) => (query||window.location.search.replace('?','')).split('&').map(e=>e.split('=').map(decodeURIComponent)).reduce((r,[k,v])=>(r[k]=v,r),{});
or full version:
const getQueryParams = (query = null) => {
return (
(query || window.location.search.replace("?", ""))
// get array of KeyValue pairs
.split("&")
// Decode values
.map((pair) => {
let [key, val] = pair.split("=");
return [key, decodeURIComponent(val || "")];
})
// array to object
.reduce((result, [key, val]) => {
result[key] = val;
return result;
}, {})
);
};
Example:
URL:  ...?a=1&b=c&d=test
Code:
getQueryParams()
//=> {a: "1", b: "c", d: "test"}
getQueryParams('type=user&name=Jack&age=22')
//=> {type: "user", name: "Jack", age: "22" }
you can check the react-router, in simple,you can use the code to get query parameter as long as you defined in your router:
this.props.params.userId
React Router Dom V6
https://reactrouter.com/docs/en/v6/hooks/use-search-params
import * as React from "react";
import { useSearchParams } from "react-router-dom";
function App() {
let [searchParams, setSearchParams] = useSearchParams();
function handleSubmit(event) {
event.preventDefault();
// The serialize function here would be responsible for
// creating an object of { key: value } pairs from the
// fields in the form that make up the query.
let params = serializeFormQuery(event.target);
setSearchParams(params);
}
return (
<div>
<form onSubmit={handleSubmit}>{/* ... */}</form>
</div>
);
}
Till React Router Dom V5
function useQueryParams() {
const params = new URLSearchParams(
window ? window.location.search : {}
);
return new Proxy(params, {
get(target, prop) {
return target.get(prop)
},
});
}
React hooks are amazing
If your url looks like /users?page=2&count=10&fields=name,email,phone
// app.domain.com/users?page=2&count=10&fields=name,email,phone
const { page, fields, count, ...unknown } = useQueryParams();
console.log({ page, fields, count })
console.log({ unknown })
In case of your query parameter contains hyphone ("-") or space (" ")
then you can not unpack like { page, fields, count, ...unknown }
You'll need to go with treditional assignment like
// app.domain.com/users?utm-source=stackOverFlow
const params = useQueryParams();
console.log(params['utm-source']);
If your Router is like this
<Route exact path="/category/:id" component={ProductList}/>
You will get that id like this
this.props.match.params.id
Say there is a url as follows
http://localhost:3000/callback?code=6c3c9b39-de2f-3bf4-a542-3e77a64d3341
If we want to extract the code from that URL, below method will work.
const authResult = new URLSearchParams(window.location.search);
const code = authResult.get('code')
do it all in one line without 3rd party libraries or complicated solutions. Here is how
let myVariable = new URLSearchParams(history.location.search).get('business');
the only thing you need to change is the word 'business' with your own param name.
example url.com?business=hello
the result of myVariable will be hello
I had a hard time solving this issue. If none of the above work you can try this instead. I am using the create-react-app
Requirements
react-router-dom": "^4.3.1"
Solution
At the location where router is specified
<Route path="some/path" ..../>
Add the parameter name that you would want to pass in like this
<Route path="some/path/:id" .../>
At the page where you are rendering some/path you can specify this to view the parameter name call id like this
componentDidMount(){
console.log(this.props);
console.log(this.props.match.params.id);
}
At the end where you export default
export default withRouter(Component);
Remember to include import
import { withRouter } from 'react-router-dom'
When console.log(this.props) you would be able what has been passed down. Have fun!
React Router v5.1 introduced hooks:
For
<Route path="/posts/:id">
<BlogPost />
</Route>
You can access params / id with hook:
const { id } = useParams();
More here.
If you aren't getting the this.props... you were expecting based on the other answers, you may need to use 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))
Actually there is no need to use 3rd party library. We can make with pure JavaScript.
consider the following URL:
https://example.com?yourParamName=yourParamValue
Now we get:
const url = new URL(window.location.href);
const yourParamName = url.searchParams.get('yourParamName');
In short
const yourParamName = new URL(window.location.href).searchParams.get('yourParamName')
Another Smart Solution (Recommended)
const params = new URLSearchParams(window.location.search);
const yourParamName = params.get('yourParamName');
In short
const yourParamName = new URLSearchParams(window.location.search).get('yourParamName')
NOTE:
use "getAll" instead of "get" for Params having multiple value
https://example.com?yourParamName[]=yourParamValue1&yourParamName[]=yourParamValue2
const yourParamName = new URLSearchParams(window.location.search).getAll('yourParamName[]')
Result will be like:
["yourParamValue1", "yourParamValue2"]
Try This
http://localhost:4000/#/amoos?id=101
// ReactJS
import React from "react";
import { useLocation } from "react-router-dom";
const MyComponent = () => {
const search = useLocation().search;
const id = new URLSearchParams(search).get("id");
console.log(id); //101
}
// VanillaJS
const id = window.location.search.split("=")[1];
console.log(id); //101
React router from v4 onwards no longer gives you the query params directly in its location object. The reason being
There are a number of popular packages that do query string
parsing/stringifying slightly differently, and each of these
differences might be the "correct" way for some users and "incorrect"
for others. If React Router picked the "right" one, it would only be
right for some people. Then, it would need to add a way for other
users to substitute in their preferred query parsing package. There is
no internal use of the search string by React Router that requires it
to parse the key-value pairs, so it doesn't have a need to pick which
one of these should be "right".
Having included that, It would just make more sense to just parse location.search in your view components that are expecting a query object.
You can do this generically by overriding the withRouter from react-router like
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)
React Router v6
Source: Getting Query Strings (Search Params) in React Router
Use the new useSearchParams hook and the .get() method:
const Users = () => {
const [searchParams] = useSearchParams();
console.log(searchParams.get('sort')); // 'name'
return <div>Users</div>;
};
With this approach, you can read one or a few params.
BONUS Get params as an object:
If you need to get all query string params at once, then we can use Object.fromEntries like this:
const Users = () => {
const [searchParams] = useSearchParams();
console.log(Object.fromEntries([...searchParams])); // ▶ { sort: 'name', order: 'asecnding' }
return <div>Users</div>;
};
Read more and live demo: Getting Query Strings (Search Params) in React Router
You can use the following react hook:
Hook state updates if the url changes
SSR: typeof window === "undefined", just checking window causes errors (try it out)
Proxy object hides implementation, so undefined is returned instead of null
So this is the function to get the search param as object:
const getSearchParams = <T extends object>(): Partial<T> => {
// server side rendering
if (typeof window === "undefined") {
return {}
}
const params = new URLSearchParams(window.location.search)
return new Proxy(params, {
get(target, prop, receiver) {
return target.get(prop as string) || undefined
},
}) as T
}
And then use it as hook like that:
const useSearchParams = <T extends object = any>(): Partial<T> => {
const [searchParams, setSearchParams] = useState(getSearchParams())
useEffect(() => {
setSearchParams(getSearchParams())
}, [typeof window === "undefined" ? "once" : window.location.search])
return searchParams
}
If your url looks like this:
/app?page=2&count=10
You can just read it like this:
const { page, count } = useQueryParams();
console.log(page, count)
this.props.params.your_param_name will work.
This is the way to get the params from your query string.
Please do console.log(this.props); to explore all the possibilities.
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
})
}
Maybe a bit late but this react hook can help you get/set values in URL query: https://github.com/rudyhuynh/use-url-search-params (written by me).
It works with or without react-router.
Below is code sample in your case:
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>
)
}
You could create simple hook for extracting search params from current location:
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
}
then you could use it inside your functional component like this:
// 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'}
Maybe someone can help clarify why but if you're attempting to hit props to find location from a fresh install of Create React App on the App.js page you get:
TypeError: Cannot read property 'search' of undefined
Even though I have App.js as the home route:
<Route exact path='/' render={props => (
On App.js only, using window.location worked for me:
import queryString from 'query-string';
...
const queryStringParams = queryString.parse(window.location.search);
In the component where you need to access the parameters you can use
this.props.location.state.from.search
which will reveal the whole query string (everything after the ? sign)

Categories