Programmatic relative links with react-router - javascript

Did somebody manage to find a good way how to programmatically navigate to a relative link with react-router?
I've used react-router-relative-links for declarative links, but I can't find a good way to do this programmatically.
I know it could be done manually with resolve-pathname and router.push(…), but that would require access to the location, which is only available on route handler components. My component is somewhat deep down the tree, therefore I'd like to avoid all the wiring back to the top.
Is window.location.pathname the right way to get the location and then use router.push available through withRouter?
Currently I'm using this as a utility function:
import resolvePathname from 'resolve-pathname';
function getPathnameFromRelativeLocation(relativeLocation) {
let {pathname} = window.location;
let basePath = pathname.endsWith('/') ? pathname : pathname + '/';
return resolvePathname(relativeLocation, basePath);
}
And in an event handler of a React component:
// Current path is `/books/123`
let path = getPathnameFromRelativeLocation('write-review');
this.props.router.push(path);
// Current path is `/books/123/write-review`

react-router 3.0 now provides location on the context so it's now easy to just take it from there.
https://github.com/ReactTraining/react-router/issues/3325

if you are using browserHistory
it's simply
browserHistory.push('/yourRelativePath');
for that make sure you have latest react-router and
import { browserHistory } from 'react-router';

Related

How can i check pathname is exist in react? [duplicate]

How to check if generic react-router path matches current location pathname?
react-router path: /Movies/:id
location.pathname: /Movies/56fa7446bae6eb301e5937f3
I want to use route paths with menu buttons, to set class="active".
EDIT:
To clarify, paths in my app look like:
/Movies/56fa7/watch
and not like:
/Movies/watch/56fa7
How do I check if the former route is active?
Is it doable without <Link> component?
/Movies/56fa7/watch is arbitrary after /Movies, and <Link> obviously can't be pointed to an arbitrary location. So let's ignore <Link> for a moment:
Is there a standalone function or property in react-router that checks if /Movies/:id/watch is active?
According to the docs, you could use matchPath function which takes two arguments:
pathname you want to match (String).
options (Object) or path (String) to match against.
If matched it will return an object of this shape:
{
path, // the path used to match
url, // the matched portion of the URL
isExact, // whether or not we matched exactly
params
}
Otherwise you'll get null.
To make use of it in your components you could simply do:
import { matchPath } from 'react-router';
// ...
render () {
const isMovieWatchPathActive = !!matchPath(
this.props.location.pathname,
'/Movies/:id/watch'
);
// ...
}
Hope it'll help someone.
As of React Router v4 (March 2017):
I'm a bit late to the party, but hopefully this will help anyone with the same question. When a component is rendered through a Route, certain props are passed to it. These props can be used to determine which route is active.
In a component rendered by a Route, you can use this.props.match.url to get the actual URL requested by the browser, and you can use this.props.match.path to get the path pattern for the current route.
Check working example here: https://codesandbox.io/s/20o7q0483j
Docs related to this are available here:
https://reacttraining.com/react-router/web/api/Route/Route-props
use this
import { matchPath } from "react-router";
const match = matchPath("/users/123", {
path: "/users/:id",
exact: true,
strict: false
});
Check out the Link's property: activeStyle or activeClassName. They are supposed to automatically set the link to active when route matches. See the example: https://github.com/reactjs/react-router-tutorial/tree/master/lessons/05-active-links

Keep param consistent on location change ReactJs

I am using react router v4 to change location in ReactJs.
this.props.history.push("/profile");
<Link to="/profile" />
The above code works fine.
Now I want to keep a param consistent in URL http://localhost:3000?source=test by using the same code as above.
One approach is that I find all the occurrences in the code and add condition that if params source=test exist then append it to the the URL as well but this approach doesn't look fine to me as I have add condition on every redirect, Link and history.push
Second approach that I find is that use of listener on location update given by react router
In my Main Route file
class App extends Component {
componentDidMount() {
this.unlisten = this.props.history.listen((location, action) => {
if (/source=ep/.test(this.props.location.search)) {
location.search = _startsWith(location.search, "?") ? location.search + "&source=test" : "?source=test"
}
});
}
}
With this approach I can easily append the params in search query of react router but the param doesn't show up in URL.
the URL looks like this http://localhost:3000/profile and When I get search params from react-router console.log(this.props.location.search) it shows the param source=test and it's exactly what I want but In this case if user refreshes on this page the search params lost from react-router as well because it's not in the URL.
Can you guys help me to keep source=test consistent even in URL.

Vue.JS - Both 'history' and 'abstract' router?

I am creating a VueJS app in which the user fills out a 5-step form.
These steps are routed to /step-1 through /step-5 in the Vue Router. However, I would like the site to return to the index page (/) when refreshing the page.
I could use abstract mode for this – but the result page is generated from the following url: /result/:userid in which I need the state to be history in order to be able to get the userid from the URL (and then do a post request to the server).
I also want this URL to be accessible even after finishing the form, so abstract here is not an option unfortunately.
So – is it possible to use both modes? Refresh the page to index.html when refreshing the form-pages, but then use history mode to render the result?
You cannot do this. It is either history or abstract but not both. Having said this, there are a couple of things you can do.
Approach 1: Use history mode with steps as query params
So instead of having routes like /step-1 or /step-2, use then as part of query params. So you will have routes like:
Index route: example.com/?step=1, example.com/?step=2
Result route: example.com/result/:userId
Approach 2: Use abstract mode with higher order component
Here, you will have a router with abstract but it will only serve as a state router and won't help with any browser URL manipulation.
Build a higher order component like AppComponent where you will have your own regular expressions to determine the route. It would look like:
// Should match route /result/:userId
const IS_RESULT = new RegExp('/result/(\\d+)$');
// User RegExp groups
const IS_STEP = new RegExp('/step-(\\d+)$');
export default class AppComponent extends Vue {
// Use Vue.js created hook
created() {
const path = window.location.pathname;
// Top level routing of the application
if (IS_STEP.test(path)) {
// Do something. You are in step-1/step-2/etc.
} if (IS_RESULT.test(path)) {
// Do something. You are in /result/:userId
// Get userId
const groups = IS_RESULT.exec(path);
const userId = groups[1];
} else {
// Goto Error page
throw new Error('Unknown route');
}
}
}
Approach 3: Use Multi-page SPA
Here, you will create two single page application. The first app will have routes /step-1, /step-2, etc. You will use abstract mode for this. The second application will have /result/:userId route with history mode.
In this architecture, when a user is on step-5, instead of pushing a new state to the router, you will use HTML5 history API to change the router and then cause a forced page refresh. Also, there are other ways you achieve this.
You can simply have a redirect in native javascript where you call it window.location.href('yourHomePage.com') and it will do a full refresh.

How to use js code to forward reactjs-router?

when u seem to require forward in reactjs we used to put a Link or button ,and then consumer click it ,then the page reload corresponding path of router . Now,I want the page turn to other path of router when I request a post and the status of response is 200. It can't use a link or button ,could reactjs use code to do this? like : CertainComponent.setPath(otherPath); CertainComponent.turn;
My English is poor , it may be not clear to delive the function which i want to do.
Thanks!
I think you want to use this.context.router.push('/users/12')
https://github.com/reactjs/react-router/blob/master/docs/API.md#routercontext
First of all the component you are using has to be a container, which means you have to create it with connect() so it has access on store and dispatch:
let MyComponent = ({ dispatch, store }) => {
store.routing.push('url');
}
export default connect()(MyComponent)
And this depends how you named the router key on your store when you combined the routing reducer from redux-router on your store.
There is also another alternative, where you could do
import { hashHistory } from 'react-router';
hashHistory.push('next-url');

Get current page path from react-routers browserHistory object

Outside of my components I need to query the current active URL. I'm going to set some classes on the body ( which is outside my react root ) based on this.
First attempt was to use
//Gets an array of class names that I can add to my body tag
getClassNames(window.location.pathname);
But it seems window.location.path isn't updated when React Router navigates. Surprising yes.
So I thought, ok maybe I can get this from browserHistory
import { browserHistory } from 'react-router'
But alas, I can't see a way to read the current page path from here either ( no decent API documentation seems to exist for this object)
Any tips? Seems like a simple problem, and it would be if window.location.pathname stayed in sync with the history object.
Ok as of 2017 at least, location is available via
browserHistory.getCurrentLocation();
const location = browserHistory.getCurrentLocation();
console.log(location);
The only way I know to do this right now is to use a listener like
import { browserHistory } from 'react-router'
browserHistory.listen(function(event) {
//manage the pathname on your own
console.log(event.pathname);
});
Not ideal, but even after looking at the DOMUtils library used by history, its implementation of getWindowPath() includes the pathname, search, and hash strings. However, looking for a docs link for you on GitHub, History seems to have received a v3 rewrite as of ~20 days ago and now includes a pathUtils module that may be useful to you.

Categories

Resources