react-router v6 history.location.search replacement - javascript

In react-router v5 I was able to use
let keyword = history.location.search
but in react-router v6 I get an error so what is the replacement for that code?
Edit: BTW I am not so good at router and currently converting a code from v5. I was wondering what should keyword return in v5? The path I am currently in?

It's was always the case that you should have accessed the search value from the location object instead of the history object.
See history is mutable
The history object is mutable. Therefore it is recommended to access
the location from the render props of <Route>, not from
history.location. This ensures your assumptions about React are
correct in lifecycle hooks.
If the tutorial is showing using history.location.search I wouldn't give it much weight.
In react-router-dom#6 however, there are no longer any route props, i.e. no history, location, or match props. You instead access these all via React hooks. Note that the history object is also no longer directly exposed out to components, replaced by a navigate function via the useNavigate hook.
To access the queryString RRDv6 introduced a new useSearchParams hook.
Given URL "/somepath?someQueryParam=123"
import { useSearchParams } from 'react-router-dom';
...
const [searchParams, setSearchParams] = useSearchParams();
const someQueryParam = searchParams.get("someQueryParam"); // 123
Additional Question
Edit: Btw I am not so good at router and currently converting a code
from v5 I was wondering what should keyword return in v5 ? The path I
am currently in?
location.search is a string, so you could process the string manually, or create a URLSearchParams object.
Check the RRDv5 Query Parameters demo
They create a custom useQueryHook:
function useQuery() {
const { search } = useLocation();
return React.useMemo(() => new URLSearchParams(search), [search]);
}
then access named query params with the getter:
let query = useQuery();
...
const name = query.get("name");

example url: https://example.com/?foo=bar
import { useSearchParams } from 'react-router-dom'
const Component = () => {
const [searchParams, setSearchParams] = useSearchParams()
const foo = searchParams.get('foo')
console.log(foo) // "bar"
return <></>
}
Obviously, you need to use this inside a router.
Note: all search param values are strings.

Related

Impossible to get part of URL with react router?

How can I always get the same part of the URL in react?
example:
http://localhost:3000/supplier/924511e8-9056-4c1e-9976-625bf042924e
I only want "supplier", but this can be anything else. So it's possible for it to be:
http://localhost:3000/product/924511e8-9056-4c1e-9976-625bf042924e
Then I want "product"
But it can also be just http://localhost:3000/supplier/ also in this case I only want the supplier. And this can be anything.
How do I do this? If I've already tried it with pathname.slice(0, pathname.indexOf("/") but this doesn't seem to work.
So I only want the string after the http://localhost:3000/want this/ no matter if there is anything after it or not.
You can use the split method as below:
const url = 'http://localhost:3000/supplier/'
const want_this = url.split('/')[3]
Just use useParams from react router dom
import {useParams} from "react-router-dom";
function Child() {
// We can use the `useParams` hook here to access
// the dynamic pieces of the URL.
let { id } = useParams();
return (
<div>
<h3>ID: {id}</h3>
</div>
);
}

Passing two paramaters in arrow function React Native

I have an arrow function in my react native application.
I am trying to pass first props to be able to navigate between my screens and at the same time I want also to pass in route because I want to pass data between my screens.
However, with the following code I have, whatever I put as the second parameter, it is always undefined... and the first one will work correctly.
Please let me know what I must do to be able to pass in two parameters:
const Home = ({route, props}) => {
{console.log(route.params.id)}
{console.log(props)}
}
I also tried
const Home = ({route}, props) => {
{console.log(route.params.id)}
{console.log(props)}
}
By the way, I am using the latest version of React Native and React Navigation. I'm using purely functional component
Normally, I use to like that
const Home = (props) => {
const {route} = props
{console.log(route.params.id)}
{console.log(props)}
}
Because in component all params are props and only one param is props in component
this not the right way to pass other props. try this.
const Home =({route, ...props}) => {
....
}

Re-render same component on url change in react

I have a route which takes an id and renders the same component for every id, for example :
<Route path='/:code' component={Card}/>
Now the in the Link tag I pass in an id to the component.Now the Card component fetches additional detail based on the id passed. But the problem is it renders only for one id and is not updating if I click back and goto the next id. I searched and found out that componentsWillReceiveProps can be used but during recent versions of React it has been deprecated. So how to do this?
Putting current location as key on component solves problem.
<Route path='/:code' component={(props) => <Card {...props} key={window.location.pathname}/>}/>
I just ran into a similar problem. I think you are conflating updating/rerendering and remounting. This diagram on the react lifecycle methods helped me when I was dealing with it.
If your problem is like mine you have a component like
class Card extend Component {
componentDidMount() {
// call fetch function which probably updates your redux store
}
render () {
return // JSX or child component with {...this.props} used,
// some of which are taken from the store through mapStateToProps
}
}
The first time you hit a url that mounts this component everything works right and then, when you visit another route that uses the same component, nothing changes. That's because the component isn't being remounted, it's just being updated because some props changed, at least this.props.match.params is changing.
But componentDidMount() is not called when the component updates (see link above). So you will not fetch the new data and update your redux store. You should add a componentDidUpdate() function. That way you can call your fetching functions again when the props change, not just when the component is originally mounted.
componentDidUpdate(prevProps) {
if (this.match.params.id !== prevProps.match.params.id) {
// call the fetch function again
}
}
Check the react documentation out for more details.
I actually figured out another way to do this.
We'll start with your example code: <Route path='/:code' component={Card}/>
What you want to do is have <Card> be a wrapper component, functional preferrably (it won't actually need any state I don't think) and render the component that you want to have rendered by passing down your props with {...props}, so that it gets the Router properties, but importantly give it a key prop that will force it to re-render from scratch
So for example, I have something that looks like this:
<Route exact={false} path="/:customerid/:courierid/:serviceid" component={Prices} />
And I wanted my component to rerender when the URL changes, but ONLY when customerid or serviceid change. So I made Prices into a functional component like this:
function Prices (props) {
const matchParams = props.match.params;
const k = `${matchParams.customerid}-${matchParams.serviceid}`;
console.log('render key (functional):');
console.log(k);
return (
<RealPrices {...props} key={k} />
)
}
Notice that my key only takes customerid and serviceid into account - it will rerender when those two change, but it won't re-render when courierid changes (just add that into the key if you want it to). And my RealPrices component gets the benefit of still having all the route props passed down, like history, location, match etc.
If you are looking for a solution using hooks.
If you are fetching data from some API then you can wrap that call inside a useEffect block and pass history.location.pathname as a parameter to useEffect.
Code:
import { useHistory } from "react-router";
const App = () => {
const history = useHistory();
useEffect(() => {
//your api call here
}, [history.location.pathname]);
};
useHistory hook from react-router will give the path name so the useEffect will be called everytime it (url) is changed
as described by #theshubhagrwl but
you can use location.href instead of location.pathname to work in all condition
import { useHistory } from "react-router";
const App = () => {
const history = useHistory();
useEffect(() => {
// do you task here
}, [history.location.href]);
};
You can use use UseLocation() from "react-router-dom"
and then use that object in useEffect dependency array.
import {useLocation} from "react-router-dom";
export default function Card() {
const location = useLocation();
useEffect(()=>{}, [location]);
return(
// your code here
);
}
In React Router v4 Adding a Switch tag after Router fixes the problem

Unable to access Query String parameters inside a React Component

Here's what I have done so far,
This is the Route that I have defined for a page
<Route path='emails/user/view/:id' component={AccountEmails} />
And here's where the Component is being rendered
const AccountEmails = ({params: {id}}) => <ReceiptsListBox url={"/api/accounts/"+id+"/receipts.json"}></ReceiptsListBox>
Now, within the render() method of the component, I tried to console.log(this.props.location.query) unfortunately this.props.location is undefined.
Here's the YouTube video that I have referred to.
react-router version 2.8.1 and react version 15.3.2
Use this:
const AccountEmails = props => {
const {id} = props.params;
return <ReceiptsListBox
url={"/api/accounts/"+id+"/receipts.json"}
{...props} // =====> notice this part, important
</ReceiptsListBox>
}
Reason is: You are passing only url in props, not all the props values that AccountEmails receives from Routes, because of that location is not available inside ReceiptsListBox component.
Solution is pass all the props that AccountEmails component receive along with one extra url value, by that way location will be available inside ReceiptsListBox component.

Question mark inside react router path

I'm trying to pass parameter inside my URL, but I have a problem with reading. I'm using react-router v4.
URL: http://localhost:3000/reset?token=123
I'm trying to read it this way:
<Route
path="/reset?token=:token"
component={Reset}/>
But this prints empty object console.log(this.props.match.params);. What is strange I have tried to change question mark to other character and looks like it solves my problem, but I would like to keep question mark anyway.
URL: http://localhost:3000/reset_token=123
<Route
path="/reset_token=:token"
component={Reset}/>
This already works console.log(this.props.match.params);. Any idea how to make question mark works also correct? Really important to me is to keep using just react-router without any external libs.
Cheers,
Daniel
How did I solved this issue.
http://localhost:3000?token=mypetismissing
export default function ({ location }) {
const urlParams = new URLSearchParams(location.search);
const token = urlParams.get('token');
console.log(myParams)
return (
<div>
{token}
</div>
)
}
You need query-string
Example:
http://yoursite.com/page?search=hello
const queryString = require('query-string')
class ProductsPage extends React.Component {
componentDidMount() {
let search = queryString.parse(this.props.location.search).search
console.log(search) // ==> hello
}
...
}
Change your path to '/reset'. That'll get the page to render with the token still in the url and you'll be able to grab that token. Happy coding :)
<Route
path="/reset"
component={Reset}/>
Extracting Query Parameters from react router path
URL: http://localhost:3000/reset?token=123
First import useLocation from 'react-router-dom
And do this inside your functional component
const { search } = useLocation();
const parameters = new URLSearchParams(search);
const token = parameters.get('token');

Categories