i am making a login page that redirect the user after a successful login to home page i am using react router dom i tried to look for a simple way to do it but i couldn't find :
import Authen from './Pages/Authen';
import Home from './Pages/Home';
import {
BrowserRouter as Router,
Route,
Link
} from 'react-router-dom';
class App extends Component {
render() {
return (
<div className="App">
<Router>
<div>
<ul>
</ul>
<Route exact path="/" component={Authen}/>
<Route path="Home" component={Home}/>
</div>
</Router>
</div>
thank you for your help i really appreciate it :)
login page that redirect the user after a successful login to home
page
Use the withRouter higher order component that comes with react-router-dom. It will give your component acess to the history prop. With the history prop you can push to any new URL.
import React from 'react'
import {withRouter} from 'react-router-dom'
class Authen extends React.Component {
onLogin = () => {
// also other authentication code
this.props.history.push('/home')
}
render() {
return (
<button onClick={() => this.onLogin()}> Login </button>
)
}
}
export default withRouter(Authen);
Related
I have managed to get my react-router to navigate to another page on my website however after it's done redirecting the link or button in this case still persists on the other page (login.js).
Can someone explain to me why this happens, and how I get it to not render on my page?
App.js
import Login from "./login";
import React from "react";
import "./App.css";
import { Routes, Route, Router } from "react-router-dom";
import { useNavigate } from "react-router-dom";
function App() {
const navigate = useNavigate();
const handleClick = () => {
navigate("/login");
}
return (
<div className="Main">
<Routes>
<Route path="/login" element={<Login />} />
</Routes>
<button onClick={handleClick} type="button" />
</div>
);
}
export default App;
Login.js
[![import React from "react";
export default function Login() {
return (
<div className="Login">
<h1>Login</h1>
</div>
)}
If you clearly look your routes are working inside a div which means anything along with routes will be shown on the page permanently even if your route changes.
In this case, there is an App component which has a Header component which renders one header if the user is logged in and one if not. There is also an Access component which renders either a Landing component if user is not logged in or Dashboard if the user is logged in. The user has access to all routes if logged in. How do I render components using react-router-dom if the user is on the Dashboard component? Currently, LeftNav should always be in view while the components in the main-content className toggle based on the route. Currently only the LeftNav and MainContent components work on "/", if navigated to /test or /test/new neither the LeftNavorTestComponentrender, however theHeadercomponent is still rendering correctly. What am I doing wrong here or how is this toggling betweenmain-content` components achieved?
import { BrowserRouter, Route } from "react-router-dom";
import Header from "./Header";
import Access from "./Access";
class App extends Component {
render() {
return (
<div>
<BrowserRouter>
<div>
<Header />
<Route exact path="/" component={Access} />
</div>
</BrowserRouter>
</div>
);
}
};
export default App;
////////////////////////////////
import Landing from "./Landing";
import Dashboard from "./Dashboard";
class Access extends Component {
renderContent() {
switch (this.props.auth) {
case null:
return;
case false:
return (
<Landing />
);
default:
return (
<Dashboard />
);
}
}
render() {
return (
<div>
{this.renderContent()}
</div>
);
}
}
export default Access;
////////////////////////////////
import { Switch, Route } from "react-router-dom";
import LeftNav from "./dashboard/LeftNav";
import MainContent from "./dashboard/MainContent";
import TestContent from "./dashboard/TestContent";
import TestContentNew from "./dashboard/TestContentNew";
class Dashboard extends Component {
render() {
return (
<div>
<div className="dashboard-wrapper" style={dashboardWrapper}>
<LeftNav />
<div className="main-content">
<Switch>
<Route path="/" component={MainContent} />
<Route path="/test" component={TestContent} />
<Route path="/test/new" component={TestContentNew} />
</Switch>
</div>
</div>
</div>
);
}
};
export default Dashboard;
Issue
The main Route in your application only ever matches and renders a route when it exactly matches "/", so when you navigate to another path it ceases to match.
Solution
I don't see where you pass auth as a prop to Access, but since it handles authentication and renders your actual routes you can simply just render it instead of a Route in App. It will always be rendered by the router and display either the landing page or the dashboard.
import { BrowserRouter, Route } from "react-router-dom";
import Header from "./Header";
import Access from "./Access";
class App extends Component {
render() {
return (
<div>
<BrowserRouter>
<div>
<Header />
<Access />
</div>
</BrowserRouter>
</div>
);
}
};
I'm trying to build a simple example project where the user is redirected to the 'contact' page upon clicking a button, using React. I'm trying to achieve this by setting the value of a state property. When I run the code I have, it does change the browser address bar URL to that of the contact page, but does not seem to actually load the component - I get a blank page instead. If I manually navigate to that URL (http://localhost:3000/contact) I can see the contents.
Here are my App.js and Contact.js files -
App.js
import React, { Component } from 'react';
import { BrowserRouter as Router, Switch, Route, Link, Redirect } from 'react-router-dom';
import Contact from './Contact';
class App extends Component {
state = {
redirect: false
}
setRedirect = () => {
this.setState({
redirect: true
})
}
renderRedirect = () => {
if (this.state.redirect) {
return <Redirect to='/contact' />
}
}
render() {
return (
<Router>
<Switch>
<Route exact path='/contact' component={Contact} />
</Switch>
<div>
{this.renderRedirect()}
<button onClick={this.setRedirect}>Redirect</button>
</div>
</Router>
)
}
}
export default App;
Contact.js
import React, { Component } from 'react';
class Contact extends Component {
render() {
return (
<div>
<h2>Contact Me</h2>
<input type="text"></input>
</div>
);
}
}
export default Contact;
Using state isn't really a requirement for me, so other (preferably simpler) methods of redirection would be appreciated too.
Since your button is nothing more than a link, you could replace it with:
<Link to="/contact">Redirect</Link>
There are many alternatives though, you could for example look into BrowserRouter's browserHistory:
import { browserHistory } from 'react-router'
browserHistory.push("/contact")
Or perhaps this.props.history.push("/contact").
There are pros and cons to every method, you'll have to look into each and see which you prefer.
I got here for a similiar situation. It's possible use withRouter (https://reactrouter.com/web/api/withRouter) to handle that.
This example was tested with "react": "^16.13.1","react-router-dom": "^5.2.0" and "history": "^5.0.0" into "dependecies" sections in package.json file.
In App.js I have the BrowserRouter (usually people import BrowserRouter as Router, I prefer work with original names) with Home and Contact.
App.js
import React, { Component } from "react";
import {
BrowserRouter,
Switch,
Route,
} from "react-router-dom";
import Home from "./pages/Home";
import Contact from "./pages/Contact";
class App extends Component
{
// stuff...
render()
{
return (
<BrowserRouter>
<Switch>
<Route path="/contact">
<Contact />
</Route>
<Route path="/">
<Home />
</Route>
</Switch>
</BrowserRouter>
);
}
}
export default App;
ASIDE 1: The Route with path="/contact" is placed before path="/" because Switch render the first match, so put Home at the end. If you have path="/something" and path="/something/:id" place the more specific route (with /:id in this case) before. (https://reactrouter.com/web/api/Switch)
ASIDE 2: I'm using class component but I believe (I didn't test it) a functional component will also work.
In Home.js and Contact.js I use withRouter associated with export keyword. This makes Home and Contact components receive the history object of BrowserRouter via props. Use method push() to add "/contact" and "/" to the history stack. (https://reactrouter.com/web/api/history).
Home.js
import React from "react";
import {
withRouter
} from "react-router-dom";
export const Home = ( props ) =>
{
return (
<div>
Home!
<button
onClick={ () => props.history.push( "/contact" ) }
>
Get in Touch
<button>
</div>
);
}
export default withRouter( Home );
Contact.js
import React from "react";
import {
withRouter
} from "react-router-dom";
export const Contact = ( props ) =>
{
return (
<div>
Contact!
<button
onClick={ () => props.history.push( "/" ) }
>
Go Home
<button>
</div>
);
}
export default withRouter( Contact );
Particularly, I'm using also in a BackButton component with goBack() to navigate backwards:
BackButton.js
import React from "react";
import {
withRouter
} from "react-router-dom";
export const BackButton = ( props ) =>
{
return (
<button
onClick={ () => props.history.goBack() }
>
Go back
<button>
);
}
export default withRouter( BackButton );
So I could modify the Contact to:
Contact.js (with BackButton)
import React from "react";
import BackButton from "../components/BackButton";
export const Contact = ( props ) =>
{
return (
<div>
Contact!
<BackButton />
</div>
);
}
export default Contact; // now I'm not using history in this file.
// the navigation responsability is inside BackButton component.
Above was the best solution for me. Other possible solutions are:
useHistory Hook (https://reactrouter.com/web/api/Hooks)
work with Router instead BrowserRouter - (https://reactrouter.com/web/api/Router)
I read all possible thread about programmatically redirection in React but I couldn't make it working.
My code looks like this (I removed as much I could to make it shorter):
import React from 'react';
import {render} from 'react-dom';
import {BrowserRouter as Router, Route, Switch} from "react-router-dom";
import {Login} from "./login/Login";
class App extends React.Component {
login(loginResponse) {
...
# Here I want to redirect but it does not work
this.props.history.push('/some-path/');
}
render() {
return (
<Router>
<div>
<div id="content">
<Messages />
<Switch>
<Route path="/" exact={true} component={Welcome} />
...
<Route path="/portal/login" render={() => <Login sendMessage={this.sendMessage} />} />
</Switch>
</div>
</div>
</Router>
);
}
}
render(<App/>, document.getElementById("app"));
I'd like to redirect when the login method is called to a different path.
With this.props.history.push('/some-path/'); I get Cannot read property 'push' of undefined.
In most of the places I read about withRouter but I could not make it work.
What am I missing to get the history?
Or what's the easiest to make the redirect work?
Thanks in advance
I think the main problem here is that I was trying to implement the redirect on the top level component.
I ended up moving a bit of login around and do the redirect from the Login component that is rendered thanks to the Route component therefore can access the history.
This is the code I used:
main.js
import React from 'react';
import {render} from 'react-dom';
import {BrowserRouter as Router, Route, Switch} from "react-router-dom";
import {Login} from "./login/Login";
class App extends React.Component {
render() {
return (
<Router>
<div>
<div id="content">
<Messages />
<Switch>
<Route path="/" exact={true} component={Welcome} />
...
<Route path="/portal/login" render={(router) => <Login router={router} sendMessage={this.sendMessage} />} />
</Switch>
</div>
</div>
</Router>
);
}
}
render(<App/>, document.getElementById("app"));
Login.js
import React from 'react';
export class Login extends React.Component {
constructor(props) {
super(props);
this.onLoginResponse = this.onLoginResponse.bind(this);
}
onLoginResponse(loginResponse) {
...
this.props.router.history.push('/portal/');
}
render() {
return (
<div id="login-form">
Login page ...
</div>
);
}
}
The nice thing of this is that now the code for handling a login response is in the Login page.
But as I wanted to store the user who logged in into the main app status I needed to do some extra work.
First off, I have read through just about every example I can find and looked through various boilerplates to see how others have done this. I am having issues loading pages when clicking <Link>'s with react-router v4. I have also installed the package react-router-connected and have been trying that out as well but no improvement can be seen (however it shows the changes in the redux-logger which is nice).
Currently, the url updates just fine and if I manually change the url and press enter, then the next page will load. But, it will not redirect if I click a link. I am also using create-react app for the project, just for your reference. My actual app is setup as the exact example from usage with react-router in the official redux docs. For simplicity, I have changed my routes to only include links to basic components that do nothing but redirect to one another.
Root.js which houses my routes
import React from 'react';
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import { Provider } from 'react-redux';
import { ConnectedRouter } from 'connected-react-router'
// import App from './App';
import NewComponent from './NewComponent';
import OldComponentent from './OldComponent';
const Root = ({ store, history }) => (
<Provider store={store}>
<ConnectedRouter history={history}>
<Router>
<Switch>
<Route exact path='/' component={OldComponentent}/>
<Route path='/new' component={NewComponent}/>
{/* <Route path='/' component={App}/>
<Route path='/:filter' component={App}/> */}
</Switch>
</Router>
</ConnectedRouter>
</Provider>
)
export default Root;
Home component
import React from 'react';
import { connect } from 'react-redux';
import { push } from 'connected-react-router';
import { withRouter } from 'react-router';
import { Link } from 'react-router-dom';
import Button from 'material-ui/Button';
class OldComponent extends React.Component {
redirectPage = () => { this.props.dispatch(push('/new')); };
redirectPage1 = () => { this.props.dispatch(push('/')); };
render() {
return (
<div>
OLD COMPONENT
<Button onClick={this.redirectPage}>Redirect new</Button>
<Button onClick={this.redirectPage1}>Redirect /</Button>
<Link to='/new'>Redirect Link</Link>
</div>
)
}
}
export default withRouter(connect()(OldComponent));
Other basic component for redirection purposes
import React from 'react';
import { connect } from 'react-redux';
import { push } from 'connected-react-router';
import { withRouter } from 'react-router';
import { Link } from 'react-router-dom';
import Button from 'material-ui/Button';
class NewComponent extends React.Component {
redirectPage = () => { this.props.dispatch(push('/')); };
redirectPage1 = () => { this.props.dispatch(push('/new')); };
render() {
return (
<div>
NEW COMPONENT
<Button onClick={this.redirectPage}>Redirect /</Button>
<Button onClick={this.redirectPage1}>Redirect new</Button>
<Link to='/new'>Redirect Link</Link>
</div>
)
}
}
export default withRouter(connect()(NewComponent));
As you can see, they are essentially the same component with minor differences. The url will change to /new or / and will also update the pathname found in the ##router/LOCATION-CHANGE state objects created by react-router-connected package. The url will also change by clicking the <Link> tag but with no redirect.
Any help on how to approach this would be greatly appreciated.
The comment posted by #Supertopoz works this.props.history.push('/pathname') works. However, after setting that up, the <Link> now works as well. I am also using withRouter (which I was before) throughout, so that was another important factor in egtting it to work.