react-router is not filling params - javascript

I'm using react router on a project and when I'm using the Link tag I'm not getting this.props.params properly filled when reading it on the new Page.
<Link to='/users/login/' params={{firstParam: 'firstParam'}} query={{firstParam: 'firstParam'}}>link</Link>
Anyone knows why it could be?
EDIT:
I've also tried doing it this way
this.refs.linkToLogin.context.router.transitionTo('/users/login', {firstParam: 'firstParam'});
EDIT2:
The route is defined this way
<Route name="users">
...
<Route name="users-login" path="/users/login" handler={UserPage} />
...
</Route>

Your link is set up correctly, I expect its an issue with your route handler. it must be configured to accept the state argument from the callback function. your routes file should look like this:
Router.run(routes, function(Handler, state){
React.render(<Handler {...state} />, document.querySelector('#foo')
})
the important thing to note here is the state argument in the callback function getting passed to the Handler component
additionally, your route needs to be configured to accept a dynamic param. The #props.query should go through correctly, but unless a dynamic segment of the url is defined, the params likely wont show up
<Route name='...' path='/users/:firstParam/login' handler={UserPage} />

Related

react-router: How do I update the url without causing a navigation/reload?

With react router I have done this up update the url:
this.props.history.push({
pathname: `/product/${this.props.product.id}`,
});
However this causes a re-render/navigation change. Is there a way to update the url without doing that?
My use case is I have a list of products and when I click on one I show a Modal and want to update the url to something like example.com/product/1 so that the link is sharable.
Wasn't able to find a solution using React Router, but was able to accomplish this using the browser's history interface by calling:
window.history.replaceState(null, "New Page Title", "/pathname/goes/here")
You can learn more about .replaceState here.
React Router's history.replace won't always work
React Router's history.replace method may or may not trigger a re-render depending on your app's route setup (e.g., you have a catch-all /* route). It does not prevent a render by definition.
replace will override the URL
this.props.history.replace({ pathname: `/product/${this.props.product.id}`})
I'm using a nice way of tricking the users that's the URL doesn't change.
To do this, you'll just need to setup your routes like this.
const Home = '/';
const About = '/ ';
const Contact = '/ ';
Notice the spaces. All characters will be counted inside the quote so it should work.
Routes.tsx
<Route exact path={Home} component={Home} />
<Route exact path={About} component={About} />
<Route exact path={Contact} component={Contact} />
Inside your About.tsx and Contact.tsx:
useEffect(() => {
window.history.replaceState(null, '', Home);
}, []);
After the user navigates to About or Contact pages, the hook will be called and run the code inside the callback function. It will remove the spaces after the component rendered.
That should be clean trick to disguise hidden URL 😂

how to check if url param entered exist in location.pathname via React

Well, I try to understand legacy code with React routes onboard.
I have an url like
/home/reports/some_report_numbers
when user changes the ulr like that:
/home/reports/some_report_numb
I want to check if "some_report_numb" exists in props, in this.props.location.pathname. If exists - fine, go that way, otherwise go another way.
Maybe it is a wrong approach at all? Well, when the report is shown and user just deletes some letters in url I need to redirect to /home/ page. To do that I need somehow to check if that report with that numbers exists at all.
Maybe it could be done via
<Route name={SomeRouteName} path='reports/:reportId' component={HomePage} />
According to the documentation of react-router-dom
Link: https://reacttraining.com/react-router/web/example/url-params
match become an object that can be used in your component. Like explain in the documentation, you have access to match object with the following steps:
Route component as this.props.match
Route render as ({ match }) => ()
Route children as ({ match }) => ()
withRouter as this.props.match
matchPath as the return value
For example, if you have the following route:
<Route path="/reports/:reportId" component={HomePage} />
In your component, you can access to this with: this.props.match because it's an object and inside it, you will have what you want.
After that, you could check what params you have in your URL.
Now, if you want to redirect the user, you can use <Redirect to={'/your/path'} />

React Router Query Parameters

I have a React application which is using react-router v2.4. I have a route defined like so:
<Router history={this.props.history}>
<Route path="/:organisationId/objects"
component={ObjectsPage}
onEnter={(state) => {
this.props.dispatch(objectsFetch(
state.params.organisationId,
state.location.query
));
}}
/>
</Router>
Essentially, this route dispatches an action to fetch some objects from an API which are then rendered in a tabular format. I would like this table to be searchable, sortable and paginated and I think it would be appropriate to store the state of the table in the URL as query parameters so it can be refreshed and browser back/forward functionality isn't broken.
In order to update my table component I make a call to browserHistory with a URI similar to this (note the query parameters):
browserHistory.push('/0f08ac61-ddbd-4c73-a044-e71b8dd11edc/objects?page=2&search=query&sort=firstname|desc');
However, this doesn't trigger react-router into thinking the route has updated as the onEnter callback is never fired even though the browser history is updated with the new query string. I think I understand why this is happening; since the query string isn't part of the defined route I guess the package won't pick the change up.
Is there a way to use react-router with query parameters like this or will I have to make my filters part of the URI?
Need to use onChange in the route definition - onEnter is called the first time you hit a route and onChange is called when the route status changes:
<Route path="/:organisationId/patients"
component={PatientsPage}
onEnter={(state) => {
this.props.dispatch(patientsFetch(
state.params.organisationId,
state.location.query
));
}}
onChange={(state) => {
this.props.dispatch(patientsFetch(
state.params.organisationId,
state.location.query
));
}}
/>

Bind specific redux action to one Route using react-router / react-router-redux

I am currently developing an application in react using redux, react-router (with pushState History) and react-router-redux. What i am currently doing is that i am binding my routes to specific components, like i saw as best practice in every documentation:
export default function (store) {
return <Route path='/' component={CoreLayout}>
<Route path="feed" components={{content: Feed}} />
<Route path="f/:id" components={{content: FeedItem}} />
</Route>
}
Then i have a Link component like the following somewhere in my Feed component, which is responsible for displaying one specific entry:
<Link to={{ pathname: '/f/' + item.id + '-' + urlSlug(item.title) }}>{item.title}</Link>
The link can then be something like /f/123. So the component FeedItem is loaded when i click on the link navigating to item 123. So far everything is working fine. I also have a specific reducer for my feeditem, connected mapstatetoprops. I think this is all done right.
But my problem or question now is the following:
I have an action called like "SHOW_FEED_ITEM". This action should be used if the user is directly navigating to the the url /f/123, but ideally also if one clicks on the Link component.
But what the router is actually doing is firing a ##router/LOCATION_CHANGE action. From within my reducer, i am able to handle this action and dispatch my own action, but wouldn't prefer this solution since i would have to parse the routing url a second time from there for redirecting into the right action for all those routes.
What i am doing right now is receiving the props.id (coming from the Route f/:id) in my mapStateToProps function and pass it to my component. This is the way my component comes up with the right id.
Now coming to my actual question..
Wouldn't it be better to also tell the Router which Action it should handle instead of just telling him which component(s) it should load?
I know i could add an onClick handler to the Link that dispatches my action but this would only affect a click on the link, no browser back/forth or even refresh user actions.
Is this maybe even already possible right now?
How do you guys handle that?
For the ones coming across the same issues and question: I found a solution react-router already provides.
There is an onEnter and onLeave attribute available for each Route. This is basically a callback function for the Route that is hooked before the route is rendered.
onEnter
<Route path="route/:id" components={{content: MyComponent}} onEnter={()=>store.dispatch(myComponentsEnterAction())} />
onLeave
<Route path="route/:id" components={MyComponent} onLeave={()=>store.dispatch(myComponentsLeaveAction())} />
So here is a complete router code of the example above:
import React from 'react'
import { Route } from 'react-router'
import CoreLayout from './layout/corelayout'
import Feed from './components/feed/feed'
import FeedItem from './components/feed-item/feed-item'
export default function (store) {
return <Route path='/' component={CoreLayout}>
<Route path="feed" components={{content: Feed}} onEnter={()=>store.dispatch(displayFeed())} />
<Route path="f/:id" components={{content: FeedItem}} onEnter={()=>store.dispatch(displayFeedItem())} />
</Route>
}
More on that can be found here:
https://github.com/reactjs/react-router/blob/master/docs/Glossary.md#route
https://github.com/reactjs/react-router/blob/master/docs/Glossary.md#enterhook

React Router Cannot Get / depending on onEnter function

I am new to React and hoping someone can shed some light on why this is happening and how to debug it.
I have the following routes defined:
export default (withHistory, onUpdate) => {
const history = withHistory?
(Modernizr.history ?
new BrowserHistory
: new HashHistory)
: null;
return (
<Router history={history}>
<Route path='/login' component={Login} />
<Route path='/' component={Home} onEnter={requireAuth} />
</Router>
);
};
requireAuth is supposed to check if the user is logged in and redirect them to the login page if not:
function requireAuth(nextState, transition) {
transition.to("/login");
}
If I leave the transtion.to call in and browse to the root URL I just see a message that says, "Cannot Get /" with no error messages in the debugger. Putting a breakpoint on that line doesn't seem to do anything.
What's especially odd is that if I replace transition.to(...) with a debugger; statement, then the method is called and routing works perfectly fine.
I must have a misunderstanding on something, any ideas on what that is?
Edit: I should add that navigating to host:port/login works fine, so I know the login route works.
Coming from an Angular background I had incorrectly assumed that routing was happening entirely client-side. It's possible to use react-router for both client-side and server side routing.
The transition.to call worked fine on the client-side, but threw an exception when server-side routing kicked in and returned the Cannot GET / page. The exception was being caught but nothing logged.
I added an if statement to see if we were running on the client:
if(window.location) {
if(!loggedIn) {
transition.to("/login");
}
}
There is probably a better way to handle this and if I figure that out eventually I'll update my answer.
According to the current docs, the onEnter hook receives a replace function as its second param. i.e.
type EnterHook = (nextState: RouterState, replace: RedirectFunction, callback?: Function) => any;
Are you using a different version of react-router? I tried looking through the alternate version docs for an onEnter hook that takes a transition object as its second param, but I didn't have much luck in finding anything.

Categories