I have just started using react-router V4 and I want to know how to get current location of router
This is my source code
import {Meteor} from 'meteor/meteor';
import React, {Component} from 'react';
import ReactDOM from 'react-dom';
import createHistory from 'history/createBrowserHistory'
import {Route, BrowserRouter as Router, Switch} from 'react-router-dom'
import {Tracker} from 'meteor/tracker';
import Signup from '../imports/ui/signUp';
import Link from '../imports/ui/link';
import Login from '../imports/ui/login';
import NotFound from '../imports/ui/notFound';
const history = createHistory();
const unauthenticatedPages = ['/', '/signup'];
const authenticatedPages = ['/links'];
const routes = (
<Router history={history}>
<Switch>
<Route exact path="/" component={Login}/>
<Route exact path="/signup" component={Signup}/>
<Route path="/links" component={Link}/>
<Route component={NotFound}/>
</Switch>
</Router>
);
Tracker.autorun(() => {
const unlisten = history.listen((location, action) => {
// location is an object like window.location
console.log(action, location.pathname, location.state)
})
const isAuthenticated = !!Meteor.userId();
console.log('location: ', location.pathname);
//const pathName =
});
Meteor.startup(() => {
ReactDOM.render(routes, document.getElementById('app'));
});
I tried according to react-router documentation to use history but I didn't get the location.
How to get current location of a route?
I don't use redux and I will appreciate an answer without it.
Thanks, Michael.
You can use the withrouter HOC for this. It will re-render the wrapped component anytime the route changes. Here's an example -
import {Meteor} from 'meteor/meteor';
import React, {Component} from 'react';
import ReactDOM from 'react-dom';
import createHistory from 'history/createBrowserHistory'
import {Route, BrowserRouter as Router, Switch} from 'react-router-dom'
import {withRouter} from 'react-router'
import {Tracker} from 'meteor/tracker';
import Signup from '../imports/ui/signUp';
import Link from '../imports/ui/link';
import Login from '../imports/ui/login';
import NotFound from '../imports/ui/notFound';
const history = createHistory();
const unauthenticatedPages = ['/', '/signup'];
const authenticatedPages = ['/links'];
const
ChangeTracker = withRouter(({match, location, history}) => {
console.log(action, location.pathname, location.state);
return false;
}),
routes = (
<Router history={history}>
<Switch>
<Route exact path="/" component={Login}/>
<Route exact path="/signup" component={Signup}/>
<Route path="/links" component={Link}/>
<Route component={NotFound}/>
</Switch>
<ChangeTracker />
</Router>
);
Meteor.startup(() => {
ReactDOM.render(routes, document.getElementById('app'));
});
Excellent help thanks - to keep live updating whether you're on an authenticated page or not, you could modify ChangeTracker as follows:
const ChangeTracker = withRouter(({match, location, history}) => {
const pathName = location.pathname;
isUnauthenticatedPage = unauthenticatedPages.includes(pathName);
isAuthenticatedPage = authenticatedPages.includes(pathName);
return false;
});
and your Tracker.autorun could look like:
Tracker.autorun(()=>{
const isAuthenticated = !!Meteor.userId();
if (isAuthenticated){
if (isUnauthenticatedPage){
history.push('/links');
}
}else{
if (isAuthenticatedPage) {
history.push('/');
}
}
});
You can get your current location from react router v4 by history.location and for the pathname you can use history.location.pathname. you can find more details about it in the official react router docs on githubReact Router Training.
So your code should be like this:
import {Meteor} from 'meteor/meteor';
import React, {Component} from 'react';
import ReactDOM from 'react-dom';
import createHistory from 'history/createBrowserHistory'
import { Route, Router, Switch } from 'react-router-dom'
import {Tracker} from 'meteor/tracker';
import Signup from '../imports/ui/signUp';
import Link from '../imports/ui/link';
import Login from '../imports/ui/login';
import NotFound from '../imports/ui/notFound';
const history = createHistory();
const unauthenticatedPages = ['/', '/signup'];
const authenticatedPages = ['/links'];
const routes = (
<Router history={history}>
<Switch>
<Route exact path="/" component={Login}/>
<Route exact path="/signup" component={Signup}/>
<Route path="/links" component={Link}/>
<Route component={NotFound}/>
</Switch>
</Router>
);
Tracker.autorun(() => {
const isAuthenticated = !!Meteor.userId();
const pathname = history.location.pathname;
//Now you can do whatever you want here
});
Important! passing history as props to BrowserRouter makes warning because by default BrowserRouter uses its version of history and ignores the history you passed, so to prevent this warning you should use { Router } from 'react-router-dom' rather than BrowserRouter and everything works in the way you expect.
Related
Everytime I execute history.push("/path") the url changes to the correct path but the 404 PageNotFound component gets renderered.
// indes.tsx
import React from 'react';
import ReactDOM from 'react-dom';
import {App} from './App';
import history from "./customHistory";
import {Router} from "react-router";
ReactDOM.render(
<React.StrictMode>
<Router history={history}>
<App/>
</Router>
</React.StrictMode>,
document.getElementById('root')
);
/// App.tsx
import React, {Component} from "react"
import {Route, Switch} from "react-router-dom";
import {FrontPage} from './components/FrontPage'
import {LoginPage} from "./components/LoginPage";
import {PageNotFound} from "./components/PageNotFound";
import {RequestPasswordResetPage} from "./components/RequestPasswordResetPage";
export class App extends Component {
render() {
return (
<Switch>
<Route path={"/"} component={FrontPage} exact={true}/>
<Route path={"/login"} component={LoginPage} exact={true}/>
<Route path={"/request_password_reset"} component={RequestPasswordResetPage}
exact={true}/>
<Route path={""} component={PageNotFound}/>
</Switch>
)
}
}
My history object is the following
// customHistory.ts
import { createBrowserHistory } from "history";
export default createBrowserHistory({});
And I call the history.push after the user requested a password reset:
// RequestPasswordResetPage.tsx
private handleSubmit(event: FormEvent<HTMLFormElement>) {
event.preventDefault();
AccountService.requestPasswordReset(this.state.email)
.then((ans: Response) => {
if (ans.ok) {
console.log("REDIRECT TO HOME");
history.push("/login");
} else {
throw Error(ans.statusText);
}
});
}
Everytime the url changes to localhost:3000/login but the PageNotFound component gets rendered.
Use react-router v5.2.0 and history v4.9.0 to make this work.
https://codesandbox.io/s/quizzical-dan-z3725
OR
Try using BrowserHistory
https://reactrouter.com/web/example/basic
seems there is some issue with customHistory when we use different version
When I was using BrowserRouter from react-router-dom, My Routes were working. But to use custom history, I replaced BrowserRouter with Router from react-router. After that my Route components are not loading properly but the url is changing properly.
Here is my codes:
AppRouter-JS:----
import React from 'react';
import { Router, Route, Switch} from 'react-router';
// import { BrowserRouter as Router,Route, Switch} from 'react-router-dom';
import {createBrowserHistory} from 'history'
import Header from '../components/Header.js';
import Dashboard from '../components/DashboardPage.js'
import CreateExpense from '../components/CreateExpensePage.js';
import EditExpense from '../components/EditExpensePage.js';
import Help from '../components/HelpPage.js';
import PageNotFound from '../components/PageNotFound.js'
import LoginPage from '../components/LoginPage.js'
export const history = createBrowserHistory();
const AppRouter = ()=>(
<Router history={history}>
<div>
<Header/>
<Switch>
<Route path='/' exact={true} component={LoginPage}/>
<Route path='/dashboard' component={Dashboard}/>
<Route path='/create' component={CreateExpense} />
<Route path="/edit/:id" component={EditExpense}/>
<Route path='/help' component={Help} />
<Route component={PageNotFound}/>
</Switch>
</div>
</Router>
)
export default AppRouter;
HeaderJS:-- (Here we have the NavLinks)
import React from 'react';
import {NavLink, Link} from 'react-router-dom';
import {connect} from 'react-redux';
import {LogoutAction} from '../Redux/Actions/AuthActions.js'
export const Header = ({logoutAction})=>(
<header>
<h1>Expense Tracker</h1>
<p><NavLink exact activeClassName='active-class' to='/'>Home Page</NavLink></p>
<p><NavLink activeClassName='active-class' to='/create'>Add Expense</NavLink></p>
<p><NavLink activeClassName='active-class' to='/help'>Help Page</NavLink></p>
<button onClick={logoutAction}>Logout</button>
</header>
);
const mapDispatchToProps = (dispatch)=> {
return {
logoutAction: ()=> dispatch(LogoutAction())
}
}
export default connect(undefined,mapDispatchToProps) (Header);
After clicking any NavLink or Link it always opens the PageNotFound component.
I actually just found my problem, and it might be yours too.
I was on react-router-dom#5.2.0 and history#5.0.0.
react-router 5x is compatible with history 4x. Once I downgraded to history#4.10.1 everything started working.
Now using useNavigate() hook instead of useHistory() or anything related to history.
You can use like this;
import { useNavigate } from "react-router-dom";
let navigate = useNavigate();
navigate('/detail')
Note:Written to update information.
i used history.goBack("/signup") not history.push("/signup") seems to work for me .
I upgrade React from v16.0.0 to the last version to use Hook, after the upgrade, React Router stop working.
This is the AppRoute code:
import React from 'react';
import { Router, Route, Switch } from 'react-router-dom';
import createHistory from 'history/createBrowserHistory';
import DashboardPage from '../components/DashboardPage';
import HelpPage from '../components/HelpPage';
import NotFoundPage from '../components/NotFoundPage';
import LoginPage from '../components/LoginPage';
import PrivateRoute from './PrivateRoute';
import PublicRoute from './PublicRoute';
export const history = createHistory();
const AppRouter = () => (
<Router history={history}>
<div>
<Switch>
<PublicRoute path="/" component={LoginPage} exact={true} />
<PrivateRoute path="/dashboard" component={DashboardPage}/>
<Route path="/help" component={HelpPage} />
<Route component={NotFoundPage} />
</Switch>
</div>
</Router>
);
export default AppRouter;
I'm getting:
Output
thank you very much!
Ori
The Router Component in react-router-dom is actually called BrowserRouter not Router , so change Router import and Tag to BrowserRouter or Just Provide an alias and it should work without changing the tag
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
and instead of createHistory use createBrowserHistory
import { createBrowserHistory } from "history";
export const history = createBrowserHistory();
Refrence here
CodeSandbox here
Try not combining logic with UI
// ...code...
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
// ...code...
const AppRouter = () => {
const [loggedIn, setLoggedIn] = useState(false)
return (
<Router>
<Switch>
{
!loggedIn
? <Route exact path="/" component={LoginPage} />
: <Route exact path="/dashboard" component={DashboardPage}/>
}
<Route exact path="/help" component={HelpPage} />
<Route component={NotFoundPage} />
</Switch>
</Router>
);
}
I have used code-splitting using React lazy. No errors are showed, but the page is not displayed. The following code is inside the index.js
What am I doing wrong?
import React from "react";
import "./index.css";
import * as serviceWorker from "./serviceWorker";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import {Suspence,lazy} from 'react';
// Imported Pages
const HomePage = lazy(() => import("./components/home_page/index"));
const MoviePage = lazy(() => import("./components/movie_page/index"));
const App = () =>(
<Router>
<Suspence falback ={<div>Loading...</div>}>
<Switch>
<Route exact path="/" component={HomePage} />
<Route exact path="/movie_page" component={MoviePage}/>
</Switch>
</Suspence>
</Router>,
document.getElementById("root")
);
serviceWorker.unregister();
export default App
I am currently experimenting with the use of React Router on the website I am building. I came across the use of React Router in order to navigate through my website, and also do other things like read parameter values etc. However, I find it to be slightly confusing. You see, on my administrator login page, the router only works some times - but I haven't really figured out when and when not. I am using this.props.history.push('/admin/dashboard'), which I believe is the correct way of doing it. This is currently my setup in index.js where i have all my routes:
import React from 'react';
import ReactDOM from 'react-dom';
import registerServiceWorker from './registerServiceWorker';
import './css-styling/styling.css'
import Frontpage from './Frontpage';
import { BrowserRouter, Route, Router, Switch, Link, NavLink } from 'react-router-dom';
import AdminLogin from './Admin-Login';
import AdminWelcome from './Admin-Welcome';
import Authentication from './components/Authentication';
const websiteRoutes = (
<Router history={history}>
<div>
<Switch>
<Route path="/" component={Frontpage} exact={true}/>
<Route path="/admin" component={AdminLogin} exact={true}/>
<Authentication props={this.props}>
<Route path="/admin/welcome" component={AdminWelcome} exact={true}/>
</Authentication>
</Switch>
</div>
</Router>
);
var appRoot = document.getElementById('root');
registerServiceWorker();
ReactDOM.render(websiteRoutes, appRoot);
And each 'component' has its structure like this:
import React from 'react';
import ReactDOM from 'react-dom';
import AdminHeader from './components/Admin-Header';
import AdminPanelLogin from './components/Admin-Panel-Add-News';
import history from './components/History';
class AdminLogin extends React.Component{
render() {
return(
<div>
<AdminHeader />
<AdminPanelLogin />
</div>
);
}
}
export default AdminLogin;
What seem to be the problem here? I have tried a lot of different solutions, without having any luck. One of them was creating this 'global history', which you can see that I have imported in my AdminAddNews class.
What is the correct way of using React Router in my case?
By the way; The history.push happens inside my AdminPanelLogin component, where the code looks like this:
import React from 'react';
import ReactDOM from 'react-dom';
import { Icon, Input, Button, Message } from 'semantic-ui-react';
import {auth} from './Firebase';
import {NotificationContainer, NotificationManager} from 'react-notifications';
import { withRouter, Redirect } from 'react-router-dom';
import history from './components/History';
class AdminLogin extends React.Component{
constructor(props){
super(props);
this.handleLogin = this.handleLogin.bind(this);
this.clickLogin = this.clickLogin.bind(this);
this.performLogin = this.performLogin.bind(this);
}
handleLogin(e){
this.setState({
[e.target.name]: e.target.value
});
}
clickLogin(e){
e.preventDefault();
auth.signInWithEmailAndPassword(this.state.email, this.state.password).then(() => {
this.props.history.push('/admin/dashboard');
}).catch((error)=> {
})
}
render() {
return (
<HTMLGOESHERE>
);
}
}
export default AdminLogin;
Few things, that you need to correct,
First: In your Routes you have passed history but you have not created a custom history anywhere. You can simply use BrowserRouter for now.
Second: Write your authentication component as Wrapper to your Routes instead of using your Routes as children to it
Authentication:
const PrivateRoute = (props) => {
const userKey = Object.keys(window.localStorage)
.filter(it => it.startsWith('firebase:authUser'))[0];
const user = userKey ? JSON.parse(localStorage.getItem(userKey)) : undefined;
if (user) {
return <Route {...props} />
} else {
return <Redirect to='/admin'/>
}
}
export default PrivateRoute;
Now you Routes can be
import { BrowserRouter as Router, Route, Router, Switch } from 'react-router-dom';
import Authentication from './Authentication';
const websiteRoutes = (
<Router>
<div>
<Switch>
<Route path="/" component={Frontpage} exact={true}/>
<Route path="/admin" component={AdminLogin} exact={true}/>
<Authentication path="/admin/welcome" component={AdminWelcome} exact={true}/>
</Switch>
</div>
</Router>
);
Apart from this check how to Programmatically Navigate with react-router
Actually, you have to use browserHistory, which is a function of react-router.I hope following snippet will help you,
Import react-router in your index.js
import {Router, Route, browserHistory} from 'react-router';
ReactDOM.render(
<Router history={browserHistory} >
<Route path="/admin/somethingZero" component={somethingZero} />
<Route path="/admin/somethingOne" component={somethingOne}/>
</Router> , document.getElementById("root")
)
you can navigate between the components, by using browserHistory.push function
clickLogin(){
browserHistory.push('/admin/dashboard')
}
Also, go on with this tutorial, it will give better understanding of routers.