How can i get :params from location? - reactjs

I would like to implement wide spread pattern mywebsite/en/welcome. In this case i have to modify all my for including actual param :lang into their prop 'to'. Without this implementation i couldn't know current language. So, i use handleLocationChange to spread curent :lang to all my components. But i receive location prop which include only current path and query. How can i receive curent :lang param too ?
p.s. i would like to avoid all of this but AFAIK react-router doesn't support relative links

When a <Route>'s component is rendered, it is passed a params prop which you can use to access the lang parsed from the URL. If you need access to this from a child component you will have to pass it as a prop to that component.
<Route path=':lang/my-page' component={MyPage} />
const MyPage = (props) => {
const { lang } = props.params
return (
<div>This page's language is: {lang} </div>
)
}

Related

How to pass multiple functional components in react route?

I have something like this,
<Switch>
<Route path="/playground/:id">
<Header></Header>
<Playground></Playground>
<Footer></Footer>
</Route>
<Switch/>
I want to pass all the functional components through the component props like this,
<Route path="/playground/:id" component={Playground}></Route>
But here I am only able to pass one component through the component props. How could I pass them all?
I want to do that because while passing the functional component through the component props, I can get the match.params.id value but when I pass the functional components by the first way, I cannot get the value of match.params.id and simply gives the error. `params undefined
So, the first question, How to pass multiple components?
And second question, Why I cannot access value of from match.params.id and how can I access although if I use the first way to pass the components?
1.You can stuff all all the elements into one component and transfer it to the router
2.To take some kind of value from the params one of the ways is to use the react-router-dom can be taken like this through the useParams hook in as stated in below
const { id } = useParams()
console.log(id)
or
const query = useParams()
console.log(query.id)

Can useParams be able to use inside App.js?

Good day, hoping that I am not bothering you guys.
Details
I have a path like this
localhost:3000/Project-1/todo-1
and Switch of Route like this
<Route path='/:project/:todo' component={Todo} />
Expected Output
When browser is in the example path, what I expected is App.js can also get params object by using useParams but shows empty. Did I misuse the hook? Thank you for the answers.
Additional Details
I did use useLocation that returns something like path but that is not my aim, it should be something like
params: {
project: 'Project-1',
todo: 'todo-1 '
}
that is returned using useParams for ease of extraction of project and todo values
I believe Route injects props to components it renders, so you should be able to pull it straight from the match prop within Todo: this.props.match.params.
You’ll have access to match objects in various places:
Route component as this.props.match
Route render as ({ match }) => ()
Route children as ({ match }) => ()
withRouter as this.props.match
matchPath as the return value
https://reacttraining.com/react-router/web/api/match
This only works for components rendered within a router on a route, i.e. the component a Route is rendering, or a child component further down the DOM tree. If App.js is rendering the router it won't have it.
If you need to do something with route params in the root App.js you can wrap it in a route, with unspecified path so it matches all routes, in your router using the render prop. Just ensure this is rendered outside any Switch components though as switches only return the first match, not all matches.
<Route
render={({ match }) => {
console.log('match', match);
// do what you need with the `match` prop, i.e. `match.params`
return null; // return null to indicate nothing should actually be rendered
}}
/>

Where should I parse a Query String in ReactRouter <Route> to pass parsed values into its render method as props to another Component

I would like to render a Component using a <Route> and pass some props down to the Component that it renders. I would like these props to originate from a query string, but I am struggling to figure out the proper location to actually parse the query.
Let's say I have the following URL:
localhost:3000/privateRegistration?fullName=JohnBaker&accessKey=a4141sbgfsd
I'm also using React-Router-Redux, this is what my routerReducer looks like at this address:
const routerReducer = {
location: {
hash: "",
pathname: "/privateRegistration",
search: "?fullName=JohnBaker&accessKey=a4141sbgfsd",
}
}
Since React-Router V4 does not natively parse query strings, I will use the node queryString module (https://www.npmjs.com/package/querystring)
const querystring = require('querystring')
const {location} = state.routerReducer
render() {
return (
<Route path='/privateRegistration' render={ () => {
const parsed = querystring.parse(location.search)
return (
<PrivateComponent
fullName={parsed.fullName}
accessKey={parsed.accessKey}
/>)}
}/>
)
}
Is there somewhere else that I should be performing the actual parse operation other than within the <Route> render prop/method? Technically I have access to the history object outside of the context of Route, but if I moved away from Redux, where else would I access this?
I could also simply pass in the entire location.search as a prop, or more simply access it within the component through the redux store without passing props at all
I am trying to see best practices but it seems there is a debate about the best way to do this here : https://github.com/ReactTraining/react-router/issues/4410
Within the render function of the Route you have access to pretty much everything. You can just pass those to your PrivateComponent:
render() {
return (
<Route path='/privateRegistration' render={ props =>
<PrivateComponent { ...props } /> // ^ HERE
} />
)
The props includes history, location and match objects with which you can do anything.

react-router v4 - How to provide params to a pure function using "component" attribute

I have the following code:
const CatalogContainer = () => (
<Match
pattern="/catalog/:id"
exactly
render={({ params }) => (
<Redirect to={`/catalog/${params.id}/titles`} />
)}
/>
)
But ESLint is throwing the following warning due to the =>, which is (AFAIK) a bad practice because it creates a new references of the render function at every call and I don't want that.
warning JSX props should not use arrow functions react/jsx-no-bind
So, I'm trying to refactor this using a dedicated yet simple component like:
const DefaultRedirect = (params) => (
<Redirect to={`/catalog/${params.id}/titles`} />
);
But, I'm having a hard time figuring out how to use it.
Firstly, I think I need to use component instead of render attribute, but I'm not quite sure and I haven't found the right documentation about it so far. (Edit: https://react-router.now.sh/Match Here is the doc for v4)
I tried several things, including the following, but it doesn't work.
<Match
pattern="/catalog/:id"
exactly
component={DefaultRedirect({ params })}
/>
I found a few examples but all of them are using React.createClass, which I would rather not use since using const appear to be the new "best" way to do things for stateless components.
One possible solution is to use a Class that extends React.Component. But it feels wrong. (And ESLint is showing errors about it)
Component should be written as a pure function react/prefer-stateless-function
class DefaultRedirect extends React.Component {
render() {
const { params } = this.props;
return (
<Redirect to={`/catalog/${params.businessMid}/titles`} />
);
}
}
From the doc about the render method: (https://react-router.now.sh/Match)
Instead of having a component rendered for you, you can pass in a function to be called when the location matches. Your render function will be called with the same props that are passed to the component.
This allows for convenient inline match rendering and wrapping.
Maybe convenient, but not considered as a good practice though.
Is there a way to do that using a pure function instead?
looks like you're close but not quite.
First, your dedicated functional component should parse params out of props like so:
const DefaultRedirect = ({ params }) => (
<Redirect to={`/catalog/${params.id}/titles`} />
);
* Note the destructuring in the function arguments.
Second, when you pass the component to Match just pass the reference, like so:
<Match
pattern="/catalog/:id"
exactly
component={DefaultRedirect}
/>
Hope this helps!
Disclaimer React Router v4 is still in alpha and its API is still in flux. Any advice here may become moot depending on the direction that v4 goes.
Each component rendered by a <Match> has a few props that are provided to it. These are location, pattern, params, isExact, and pathname. The last three are only provided when the pattern matches the current location.pathname.
For a component that will be rendered for a <Match>, you can destructure the params prop out of the props passed to it.
const DefaultRedirect = ({ params }) => (
<Redirect to={`/catalog/${params.id}/titles`} />
);
You can just pass that component to the <Match> then.
<Match
pattern="/catalog/:id"
exactly
component={DefaultRedirect}
/>

Read the current full URL with React?

How do I get the full URL from within a ReactJS component?
I'm thinking it should be something like this.props.location but it is undefined
window.location.href is what you're looking for.
If you need the full path of your URL, you can use vanilla Javascript:
window.location.href
To get just the path (minus domain name), you can use:
window.location.pathname
console.log(window.location.pathname); //yields: "/js" (where snippets run)
console.log(window.location.href); //yields: "https://stacksnippets.net/js"
Source: Location pathname Property - W3Schools
If you are not already using "react-router" you can install it using:
yarn add react-router
then in a React.Component within a "Route", you can call:
this.props.location.pathname
This returns the path, not including the domain name.
Thanks #abdulla-zulqarnain!
window.location.href is what you need. But also if you are using react router you might find useful checking out useLocation and useHistory hooks.
Both create an object with a pathname attribute you can read and are useful for a bunch of other stuff. Here's a youtube video explaining react router hooks
Both will give you what you need (without the domain name):
import { useHistory ,useLocation } from 'react-router-dom';
const location = useLocation()
location.pathname
const history = useHistory()
history.location.pathname
this.props.location is a react-router feature, you'll have to install if you want to use it.
Note: doesn't return the full url.
Plain JS :
window.location.href // Returns full path, with domain name
window.location.origin // returns window domain url Ex : "https://stackoverflow.com"
window.location.pathname // returns relative path, without domain name
Using react-router
this.props.location.pathname // returns relative path, without domain name
Using react Hook
const location = useLocation(); // React Hook
console.log(location.pathname); // returns relative path, without domain name
You are getting undefined because you probably have the components outside React Router.
Remember that you need to make sure that the component from which you are calling this.props.location is inside a <Route /> component such as this:
<Route path="/dashboard" component={Dashboard} />
Then inside the Dashboard component, you have access to this.props.location...
Just to add a little further documentation to this page - I have been struggling with this problem for a while.
As said above, the easiest way to get the URL is via window.location.href.
we can then extract parts of the URL through vanilla Javascript by using let urlElements = window.location.href.split('/')
We would then console.log(urlElements) to see the Array of elements produced by calling .split() on the URL.
Once you have found which index in the array you want to access, you can then assigned this to a variable
let urlElelement = (urlElements[0])
And now you can use the value of urlElement, which will be the specific part of your URL, wherever you want.
To get the current router instance or current location you have to create a Higher order component with withRouter from react-router-dom. otherwise, when you are trying to access this.props.location it will return undefined
Example
import React, { Component } from 'react';
import { withRouter } from 'react-router-dom';
class className extends Component {
render(){
return(
....
)
}
}
export default withRouter(className)
Read this I found the solution of React / NextJs. Because if we use directly used the window.location.href in react or nextjs it throw error like
Server Error
ReferenceError: window is not defined
import React, { useState, useEffect } from "react";
const Product = ({ product }) => {
const [pageURL, setPageURL] = useState(0);
useEffect(() => {
setPageURL(window.location.href);
})
return (
<div>
<h3>{pageURL}</h3>
</div>
);
};
Note:
https://medium.com/frontend-digest/why-is-window-not-defined-in-nextjs-44daf7b4604e#:~:text=NextJS%20is%20a%20framework%20that,is%20not%20run%20in%20NodeJS.
As somebody else mentioned, first you need react-router package. But location object that it provides you with contains parsed url.
But if you want full url badly without accessing global variables, I believe the fastest way to do that would be
...
const getA = memoize(() => document.createElement('a'));
const getCleanA = () => Object.assign(getA(), { href: '' });
const MyComponent = ({ location }) => {
const { href } = Object.assign(getCleanA(), location);
...
href is the one containing a full url.
For memoize I usually use lodash, it's implemented that way mostly to avoid creating new element without necessity.
P.S.: Of course is you're not restricted by ancient browsers you might want to try new URL() thing, but basically entire situation is more or less pointless, because you access global variable in one or another way. So why not to use window.location.href instead?

Resources