React Router 4 - How to append path to existing query - reactjs

I am writing an webapp that only loads when you are on a url with a query, for example:
http://localhost/site/?runapp=1
And I want to use React Router 4 in the app, but when I add a Route with a path, such as:
<Route path="/somepage" component={somePage} />
And the user clicks a:
<Link to="somepage">
to load that Route the url gets converted to:
http://localhost/site/somepage
And on refresh, the app stops working as the query is gone. How can I make React Router 4 append the paths to the needed query? I know it doesn't look pretty, but essentially I need it to route like to this url:
http://localhost/site/?runapp=1/somepage
That would make it all work, I think.
Is there a way to achieve this?
EDIT: I realized that I can simply add the ?runapp=1 in every Link to get the url to be "correct", i.e:
<Link to="?runapp=1/somepage">
but it seems hacky and doesn't allow the Route to load.

Related

How add ability add query params for gatsby routes?

How to generate pages in gatsby that will allow you to add parameters to the routing like https://page1?someParam=param or https://page1/param
What I mean? When we navigate to page page1 in gatsby it work's fine, but what if I just want add uniq params for page for google analitics? so for this I want to have ability
add some additional params for the page from where I made redirect, but when I add
for page1 some params like https://page1?someParam=param or https://page1/param, it updated and show me just https://page1 instead.
I suppose that it's related to way how I created pages. Here is my code:
createPage({
path: `${localePrefix}/${slug}`, // so should I change it here in order to work as needed?
component: PageTemplate,
context: {
...context,
localizedPaths,
},
})
Can it be fixed with?
matchPath: path: ${localePrefix}/${slug}?*,
matchPath: path: ${localePrefix}/${slug}/*,
Recap:
My question is about why gatsby remove query params from pages?
https://some_site/some_page?some_param=323
translates into
https://some_site/some_page
https://page1?someParam=param or https://page1/param are not the same. While a query parameter (first case: ?someParam=param) is an optional value that doesn't change the rendered page (it doesn't point to any specific route hence it's not requesting any file). The second one (https://page1/param) is accessing a /pages/param route.
Since they are URL parameters, you don't need to change anything in your project, you just need to catch them using JavaScript. They are handled in thee:
const urlParams = new URLSearchParams(window?.location?.search);
Note: you can access directly location prop in Gatsby
If your project is replacing https://some_site/some_page?some_param=323 to https://some_site/some_page it's because some server-side configuration or a CDN, not because of Gatsby's behavior, like any other React project.

How to view the list of history paths in react-router?

Is it possible to view the list of paths in the history object? I can see that there is the length but I need to see the actual paths.
The reason for this is for debugging purpose. I have 2 views (SPA) that gets displayed via their corresponding URL. But my problem is when I go from the first page to the next page and then I wanted to go back to the first page, I need to click the browser back button 2 times before it goes back to the first page. That's the reason I wanted to see what are the paths in the history object so I can check what entries are being added because as far as I can see, the code I have to add a path to the history object is straightforward:
props.history.push("/classes/" + courseId);
That's just the code so I don't know why I need 2 clicks to go back to the previous page.
Not exactly sure how to see the history stack, but you might be unintentionally rendering the page twice, so the history.push is working as intended. You can log in componentDidMount to see if it does, and be careful when using useEffect because that can cause that as well. If you're using react router check how the route is added in your app.js (for ex do <Route path="/classes/:courseId" component={courseId}> instead of <Route path="/classes/:courseId" render={()=>courseId()}>.

Change the route but dont navigate in React + React Router Dom

I am using a multiple step form, this one: https://material-ui.com/getting-started/templates/checkout/
It works perfectly. But i need to update the url when I change the step.
My first thought was to use a redirect, but it seems very complicated.
if (newCheckout) return <Redirect to={`checkout/${newCheckout}`} />;
Is there any way to achieve that without redirecting?.
I dont want to lose the data from my component. Just update the route.. .

Show/Hide route components in react

I am working on a React application which has routes like so:
<Switch>
<Route path="/edituser/:username" component={EditUser}/>
<Route path="/createuser/:type" component={EditUser}/>
<Route path="/listusers" component={ListUsers}/>
</Switch>
ListUsers component shows a table with pagination where each component in the table has a link which points to /edituser/:username.
I can edit users by clicking on the item in the table but as expected with react, once I go back to listusers/ the component is loaded again and I will be on the first page of users. I want to be on the page from where I accessed the user in the first place.
What is the best pattern to achieve this? I thought about passing in the page number to /edituser and then back to /listuser but then again I have to load all the paginated results again. Is local storage the only option? Any pointers are much appreciated.
There are two solutions for your problem:
1) Pass last active page ad route parameter and set your pagination accordingly.
<Switch>
<Route path="/edituser/:username" component={EditUser}/>
<Route path="/createuser/:type" component={EditUser}/>
<Route path="/listusers/:pageNumber" component={ListUsers}/>
</Switch>
on your componentDidMount you can use it to set state. For example :
const pageNumber = this.props.match.params.pageNumber;
2) Pass state prop in your routing. For example :
<Link
to={{
pathname: '/listusers',
state: { pageNumber: 1 }
}}/>
on your componentDidMount you can use it to set state. For example :
const pageNumber = this.props.location.state.pageNumber;
You could add the page number to the URL in the /listusers endpoint. Maybe something like /listusers/2 or /listusers?page=2 this way, when you hit the browser's back button, you're directly there. One last thing you could do but I wouldn't advise in this case is to store the page number in the history state.
As a rule of thumb, in order to get back, prefer using the history than using local storage.
If you really want to keep the data in memory, you can always use a store that is in a higher component (the root component for example) and keep the previous query over there. However you'll need to be careful about a lot of routing issues in such cases:
cache invalidation: the data changed on the server side in the mean time
user somehow gets back to a page with another table page number
loaded user presses the browser back button

Automatic Deep Sub-Route Redirecting in React-Router

I have recently been transitioning a project from AngularJS + UI-Router+ UI-Router-Extras to React + React-Router.
One of the better features in UI-Router-Extras that I'd like to bring to React-Router is called
Deep State Redirect. In this feature, when navigating to a route which has subroutes, the application knows to redirect the user to the last subroute of it that was visited, or if none of its subroutes have yet been visited then it redirects to its first subroute to have been registered.
So for example if the loaded routing tree looks like this:
/main
|_/main_sub_1
|_/main_sub_2
/secondary
and the user starts at route /main/main_sub_2, then goes to /secondary, then goes to /main, they will be automatically redirected to /main/main_sub_2 since /main/main_sub_2 is the last subroute of /main to have been visited.
I know that I could implement this in react router by using
<IndexRedirect to={getLastSubRoute(parentRoute)}> where parentRoute is the full path of the parent <Route> tag, and getLastSubRoute is self-explanitory, but the problem with this is that I would need to add such an <IndexRedirect> tag to every single route I create, which is not optimal since the routes are loaded dynamically, there may be up to 100 subroutes, and much of the application's routing will be written by other people who I shouldn't be relying on to remember to add that tag under every <Route> tag they write.
Ideally, I should be able to apply some function or mixin to the base <Router> tag in the React routing definition to add this functionality to all routing underneath it, but I'm not sure where to start. How might I solve this problem?
Your best bet and possibly the simplest solution would be to set an onChange hook on one of the top level routes. The hook would get called with the next parameter, which would be the next route that the user would be going to.
You would also have the hierarchical structure of routes there (navigating through to parent and children of the parent), so you could dynamically redirect using the replace function, that gets passed in as a parameter also.
I implemented something similar for permission and role management. What I also did was to .bind my store to the function that I pass into the route hook. You could possibly store the route you'd like to redirect to on the user in the state tree. Basically what you refer to as getLastSubRoute.
...
<Route onChange={myRedirectFunctionThatHasStoreBound} .. >
... // other routes
</Route>
...
function myRedirectFunctionThatHasStoreBound(store, prev, next, replace, callback) {
const user = store.getState().user;
const redirectTo = getLastSubRouteForRoute(user, next);
if (redirectTo) {
replace(redirectTo);
}
// don't forget this is you list callback as a param
// your app might stop working, explanation below
callback();
}
If callback is listed as a 4th argument, this hook will run asynchronously, and the transition will block until callback is called.
EDIT: Keep in mind that this will only work if you are using react-router that's newer than or equal to in version to react-router 2.1

Resources