How to send MULTIPLE params with useHistory hook in React? - reactjs

history.push({pathname: '/search?', state: {param1: 'value1'}}) this doesn't work. It just redirects to /search
history.push('/search?', {param1: 'value1'}) this doesn't work.
history.push('/search?', ['param1=value1']) this doesn't work.
history.push('/search?', [... 'param1=value1']) this doesn't work.
history.push('/search?', state: {param1: 'value1'}) this doesn't work.
The only thing that works is this: history.push('/search?param1=value1').
But I need to dynamically send multiple params. How do I do that? The official documentation shows the first example with an object, but it's not working for me. I am using functional components by the way.

If I understand your question correctly you want to dynamically get/set the queryString parameters of the URL.
None of the examples you've shared work because the second argument to history.push is route state.
history.push(path|To, [state])
Trying to pass queryString parameters in the second argument doesn't work.
Use URLSearchParams to construct a searchParams object that you can then update the params of, to be used in the history.push method. This method persists any existing queryString parameters.
Example:
const { search } = useLocation();
...
// get the search params for the current location
const searchParams = new URLSearchParams(search);
// update params as necessary, i.e. set/delete
searchParams.set("param1", "value1");
searchParams.set("param2", "value2");
searchParams.set("param3", "value3");
// push new route using to object
history.push({
pathname: "/search",
search: searchParams.toString(),
});
OFC, if you don't need this level of control and just need to inject the three dynamic values you could just use a template string.
history.push(`/search?param1=${value1}&param2=${value2}&param3=${value3}`);

How about this?
history.push('/search?param1=value1&param2=value2')

Related

Changing Query paramers while staying on the same page without reload= NextJS Router

for a project I am working on I am running into a problem with the nextjs Router.I have a component that has an input field which the user should be able to input their searchterm in. There is a different component which should be able to get this searchterm and perform a search.
Because the two components aren't connected I would like to set the queryParameters in the router in the Input component, and then execute a function in the search component when the searchTerm is changed.
The problem lies in the following: The searchComponent receives the nextJS router as props and will only execute my useEffect function when those props are changed (and react knows they are changed), on top of that I need to stay on the same page when updating the query parameters, but the route of this page is dynamic. For example: the user can add this combination of components on /search but also on /lookforitem.
I have tried setting the queryParameters in the following way in the Input component:
function setQueryParams() {
router.query = {
...router.query,
searchTerm: input.current,
};
}
In combination with the following code in the Search component:
useEffect(() => {
console.log('Router has changed');
}, [router]);
The problem is that this useEffect doesnt get called untill the search component is rendered again (I have created a button that logs the router to the console, and it shows the updated router), which I assume is because React hasn't realised that the Router props have changed.
I have also tried setting the query parameters via a router.push in the following way:
function setQueryParams() {
router.push(
{
pathname: router.route,
query: {
...router.query,
searchTerm: input.current,
},
},
undefined,
{ shallow: true }
);
}
However this comes with its own set of problems. First of all it causes a refresh of the page, which I don't want. On top of that it changes the url to for example: /search?searchTerm=Hello which means that if I enter a different input and submit it will stack making the next url for example: &searchterm=hello?searchterm=goodbye.
I want a way to update the query parameters without refreshing the page, but while also notifying the other components that use the router that the query parameters have updated. All of the searching that I've done seems to be specific to either routing to a different page or routing to a predefined page.
Any help would be greatly appreciated.

React router keep query params when changing route and back

I have a website with different pages based on react-router v4. Each page have url query based filters it means filter setting are stored on url like mysite.com/page1?filterKey=value.
My goal is to keep filter values on query when user back from another page ( mysite.com/page2).
The only 2 ways I see is either to use redux as Will Jenkins suggested, or to set the state in the parent container (either App.js, or the file handling your routes) :
In the parent container, define the function
setQuery = query => this.setState({query})
Pass the function to the child component
In the child component, pass the query on componentDidMount :
componentDidMount (){
this.setQuery( decodeURIComponent(querySearch(this.props.location.search).param) )
}
I found other one solutions using react hooks based global state:
const [podcastsUrlSearch, updateGlobalState] = useGlobalState('podcastsUrlSerach')
useLayoutEffect(() => {
if (!isEqual(props.location.search, podcastsUrlSearch)) {
updateGlobalState(props.location.search)
}
if (podcastsUrlSearch) {
props.history.replace({ ...props.history.location, search: podcastsUrlSearch })
}
}, [])
useLayoutEffect(() => {
updateGlobalState(props.location.search)
}, [props.location.search])
For example using a dropdown as a filter
use -->localStorage.setItem("companyDrpDwnValue")
on onChange event
and call the the below method to intialize the param on ComponentDidMount ,with which you were filtering the table
and filter the array with the filter param to get your filtered array

How to update query param in url in React?

I am trying to create pagination in my web application using react-js-pagination. Pagination is showing in webpage but i want to change page param inside url according to page number like &page=4. I tried to use
this.props.history.push(`${window.location.search}&page=${pageNumber}`)
but this is appending &page=4 everytime i click on pagination link. I know this wrong way to update url. How can i update only page parameter according to pageNumber in url?
handlePageChange = (pageNumber) => {
this.setState({activePage: pageNumber});
this.props.history.push(`${window.location.search}&page=${pageNumber}`)
}
<Pagination
activePage={this.state.activePage}
itemsCountPerPage={10}
totalItemsCount={100}
onChange={this.handlePageChange}
/>
You could use location.pathname instead of location.search but all the other query parameters will also be deleted.
So if you have other parameters that you need and you only want to change the page parameter, you can use the URLSearchParams javascript object which will make it easier to replace the current pagination.
So do as follows:
Create a new variable which contains the current url with all the params:
let currentUrlParams = new URLSearchParams(window.location.search);
Then change the page parameter to the value you need in that variable:
currentUrlParams.set('page', pageNumber);
Now push the current url with the new params using history.push:
this.props.history.push(window.location.pathname + "?" + currentUrlParams.toString());
So the full code will be:
let currentUrlParams = new URLSearchParams(window.location.search);
currentUrlParams.set('page', pageNumber);
this.props.history.push(window.location.pathname + "?" + currentUrlParams.toString());
I think you should use pathname instead of search:
this.props.history.push(`${window.location.pathname}&page=${pageNumber}`)

React Router: Query Param Match?

According to the accepted answer to this question, React Router 4 doesn't match query parameters anymore. If I go from a URL matched by one of my <Route>s to the same URL with a different query string, the content doesn't seem to change. I believe this is because navigating between URLs that match the same <Route> doesn't change the content, but please correct me if I'm wrong. Given this, how do I use React Router for a set of URL's that need to differ only by query parameter?
For example, many search engines and other sites that use search bars, including the site I am working on, use a query parameter, commonly q or query. The user may search for one thing, then decide that is not what he/she wants and search for another thing. The user may type in the second URL or search with the search bar again. There isn't really a place for the search term in the URL path, so it kind of needs to go in the query string. How do we handle this situation?
Is there a way, with React Router, to link to a URL that only differs in the query string and change the content, without refreshing the entire page? Preferably, this wouldn't require any external library besides React and React Router.
Try the render function prop instead of component prop of Route. Something like this:
<Route render={props => {
// look for some param in the query string...
const useComponentA = queryStringContains('A');
if(useComponentA) {
return <ComponentA {...props}/>;
} else {
return <ComponentB {...props}/>;
}
}}/>
There are 2 ways to do that:
1) Use location.search in react component to get the query string, then pass it to child component to prevent re-rendering the whole component. React-router has the official example about this.
2) Define a regex path of router to catch the query string, then pass it to react component. Take pagination as an example:
routes.js, for router config you can refer this
const routerConfig = [
{
path: '/foo',
component: 'Foo',
},
{
path: '/student/listing:pageNumber(\\?page=.*)?',
component: 'Student'
},
Student.js
render() {
// get the page number from react router's match params
let currentPageNumber = 1;
// Defensive checking, if the query param is missing, use default number.
if (this.props.match.params.pageNumber) {
// the match param will return the whole query string,
// so we can get the number from the string before using it.
currentPageNumber = this.props.match.params.pageNumber.split('?page=').pop();
}
return <div>
student listing content ...
<Pagination pageNumber = {currentPageNumber}>
</div>
}
Pagination.js
render() {
return <div> current page number is {this.props.pageNumber} </div>
}
The 2nd solution is longer but more flexible. One of the use cases is server sider rendering:
Apart from the react components, the rest of the application (e.g. preloaded saga) need to know the url including query string to make API call.

React Router - pass path id to onEnter function

I was previously using React Routers URL params to filter an array of content and return the specific content I wanted (filtered by ID). I have now been supplied with a separate API which means I no longer have to return all content and then filter through it, instead I can make one call and return that specific items data.
To make the call on page load I would need to access the id on the Route onEnter function. Is it possible to use a URL param on this onEnter function, and if not - would firing the dispatch function from the container component be the obvious solution?
<Route
path={'locker/my-content/:id'}
component={ManageContentPage}
onEnter={() => { store.dispatch(loadMyContent(// NEED ID HERE)); }}
/>
You can access URL params through onEnter function's argument nextState. Here's an example: React-router - how to use route params in onEnter?
If you're using react-router 4+, then the onEnter prop no long exists, and you'll have to use the render prop to achieve similar functionality.
For react-router < 4
Any function passed to onEnter will take nextState as its argument. This state object will contain your params
So to access this value, you'd need something like the following:
<Route
path={'locker/my-content/:id'}
component={ManageContentPage}
onEnter={(nextState) => { store.dispatch(loadMyContent(nextState.params.id)); }}
/>

Resources