React router keep query params when changing route and back - reactjs

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

Related

How to send MULTIPLE params with useHistory hook in React?

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

React - history.push is not working- when only query is changed

I have URL like :http://localhost:8000/main/target/:targetId/id/d:id?query=x,y
On an action I need to update url and that am doing using history.push.
now I have two scenarios and one is working other one is not :
first and working scenario- if history.push tries to update url with new value for :targetId or :id along with url query - then url gets updated and rerendering happens. Things works for me
second and not working scenario - if :targeted and:id in url remains same and I just try to change the query- url doesnt get updated using history.push.
Need to handle the second scenario and want to update url and update components based on updated url.
I have one action to update url on click:
const onElClick = e => {
const targetId = e.target;
const id= e.id;
const query = `${e.name},${e.color}`
history.push(
`/main/target/${targetId}/id/${id}?query=${query}`
);
};
And on the target page, I'm using useEffect to capture the change:
useEffect(()=> {
....
}, [window.location.search]);

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.

How to use onClick event on Link: ReactJS?

In React router, I have to and onClick attributes as shown below
<li key={i}><Link to="/about" onClick={() => props.selectName(name)}>{name}</Link></li>
state = {
selectedName: ''
};
selectName = (name) => {
setTimeout(function(){this.setState({selectedName:name});}.bind(this),1000);
// this.setState({selectedName: name});
}
to attribute navigates to about Route
onClick assigns value to state variable selectedName which will be displayed when navigated to About page.
When I give timeout insided function called on click, its navigating to new page and after sometime state is getting updated resulting in displaying previous name until state is updated with new name.
Is there a way where it will navigate to the new route only after the code in onClick function gets executed.
You can get the entire code [here].(https://github.com/pushkalb123/basic-react-router/blob/master/src/App.js)
One possible way is, Instead of using Link, use history.push to change the route dynamically. To achieve that remove the Link component and define the onClick event on li. Now first perform all the task inside onClick function and at the end use history.push to change the route means to navigate on other page.
In your case change the router inside setState callback function to ensure that it will happen only after state change.
Write it like this:
<li key={i} onClick={() => props.selectName(name)}> {name} </li>
selectName = (name) => {
this.setState({ selectedName:name }, () => {
this.props.history.push('about');
});
}
Check this answers for:
When to use setState callback
How to navigate dynamically using react router dom
Alternatively, I would recommend using URL Params in order to capture the name of the person that the about page is about. Thus, instead of the url being /about and the name being behind the scenes, it would be /about/tom or /about/pushkal. The way that you do this is by defining params in the URL router as such in your index.js:
<Route path="/about/:name" component={AboutPage}>
Now, when you link to the about page, you would do it as such:
<Link to={"/about/" + name}>{name}</Link>
Now, in your AboutPage component, you can access the name param as a prop in this.props.params.name. You can look at more examples here.
This method is a bit different than your current approach but I suspect it will lead to easier design later on

React Router "Link to" does not load new data when called from inside the same component

Background
I am building an app with the following details
react
react-router
redux
it is universal javascript
node js
Problem
When routing with the Link tag from component to component it works perfectly. It calls the data that the component requires and renders the page. But when I click on a Link that uses the same component as the current one all I see is the url change.
Attempts
Things I have tried to get this to work.
Attempt 1
So far I have tried the steps in this question but the solution wont work for me. This was the code I implemented
componentWillReceiveProps(nextProps) {
if (nextProps.article.get('id') !== this.props.article.get('id')) {
console.log('i got trigggerd YESSSSSSSSSSSSSSS');
}
}
But the variable nextProps is always the same as the current props.
Attempt 2
I decided to call the same code I use in componentWillMount but that didn't work either.
componentWillMount() {
let { category, slug } = this.props.params;
this.props.loadArticleState({ category, slug });
}
It just creates an infinite loop when I put this into componentWillReceiveProps.
Conclusion
I belief the problem is clicking the link never calls the data associated with it. Since the data is loaded with
static fetchData({ store, params }) {
let { category, slug } = params;
return store.dispatch(loadArticleState({ category, slug }));
}
Any help is appreciated.
Solution I Used
I created a function to test if the previous data is the same as the changed data.
compareParams(prevProps, props) {
if (!prevProps || typeof prevProps.params !== typeof props.params) {
return false;
}
return Object.is(props.params, prevProps.params);
}
So this tests
are there any previous props?
and then if the props are equal to the previous props?
then return false if there are if this is the case
if not then we see compare props and previous props parameters
In ComponentDidUpdate
In the compoonentDidUpdate we use this function to determine if the data should be updated
componentDidUpdate(prevProps) {
if (this.compareParams(prevProps, this.props)) {
return;
}
this.props[this.constructor.reducerName](this.props.params);
}
Conclusion
This code updates the body of a page that uses the same react component if it receives new data.
maybe you can try use onChange event on Route component, check Route API and then signal to child component that refresh is needed...

Resources