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.
Related
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'm a beginner in React and I'm learning how to route. My page changes urls, but the view turns to a blank page. My index page is working fine. I don't have any console errors.
In Router.js
import React from "react";
import {
BrowserRouter,
Route,
Switch,
} from "react-router-dom";
import App from './App'
import SinglePriceGrid from './component/SinglePriceGrid'
function Router() {
return (
<BrowserRouter>
<Switch>
<Route exact path="/" component={App} />
<Route path="/single-page-grid" component={SinglePriceGrid} />
</Switch>
</BrowserRouter>
)
}
export default Router
In SinglePriceGrid.js
import React from 'react';
import '../css/SinglePriceGrid.css'
class SinglePriceGrid extends React.Component {
render() {
return (
<div className="SinglePriceGrid">
<h1>Hello Single Price Grid!</h1>
</div>
);
}
}
export default SinglePriceGrid;
edit: Added the imports I used
edit: Readded the Switch, but it did not solve the problem
keep the Routes inside Switch. Try this
import React from "react";
import {
BrowserRouter,
Route,
Switch,
} from "react-router-dom";
import App from './App'
import SinglePriceGrid from './component/SinglePriceGrid'
function Router() {
return (
<BrowserRouter>
<Switch>
<Route exact path="/" component={App} />
<Route path="/single-page-grid" component={SinglePriceGrid} />
</Switch>
</BrowserRouter>
)
}
export default Router
I'm really sorry, but the error is really humiliating. My path is wrong. I used "page" instead of "price" for the endpoint.
// this is my index.js
import React, { } from "react";
import ReactDOM from "react-dom";
import { Provider } from "react-redux";
import store from "./store/configureStore";
import { Router } from "react-router";
import "./index.css";
import App from "./App";
import history from "./history";
// append app to dom
ReactDOM.render(
<Provider store={store}>
<Router history={history}>
<App />
</Router>
</Provider>,
document.getElementById("root")
);
//this is my app.js
import React, { Component } from 'react';
import { Route, Switch, BrowserRouter } from 'react-router-dom';
import Inscription from "../src/pages/inscription";
class App extends Component {
render() {
return (
< BrowserRouter>
<Route exact path="/" component={Inscription} />
</ BrowserRouter>
);
}
}
export default (App);
I am having changing the view in react with routing. It seems I have tried everything I can google with no luck. the page affiche but doesn't load
Please same one can help mee :(
Try removing the BrowserRouter from the App component. You have already provided a Router in index.js. Also in case you want to define multiple routes, you have to use switch
<Switch>
<Route exact path="/" component={Inscription} />
<Route exact path="/hello" component={HelloComponent} />
<Switch>
I have been unable to hide the sidebar and Navbar for some components which include login, signup, forget-password and reset-password confirm-verification
i have tried almost every everyone available to me using the stackoverflow, but none was able to work for me including [blog]:https://medium.com/#sandip21/how-to-hide-navbar-footer-on-authentication-pages-in-reactjs-40714ee1ce48, yet i couldn't get it to work
here is my app.js code
import React from 'react';
import {BrowserRouter as Router, Route, Switch} from 'react-router-dom';
import {withRouter} from 'react-router-dom'
import Header from './component/layout/Header';
import Sidebar from './component/layout/Sidebar';
import Shipped from './component/pages/Shipped';
import Warehouse from './component/pages/Warehouse';
import Assisted from './component/pages/Assisted';
import Login from './component/auth/Login'
import Reset from './component/auth/Resetpass'
import ConfirmEmail from './component/auth/ConfirmEmail'
import Signup from './component/auth/Register'
import Profile from './component/pages/Profile';
import jwt_decode from 'jwt-decode';
import setAuthToken from './utils/setAuthToken';
import { Provider } from 'react-redux';
import PrivateRoute from './component/common/PrivateRoute';
import store from './store';
function App() {
return (
<Provider store={store}>
<Router>
//this is the pages i want to hide the <Header/> and <Sidebar/> from
<Route exact path="/" component ={Login}/>
<Route exact path="/Signup" component ={Signup}/>
<Route exact path="/Reset" component ={Reset}/>
//this is where they ends
<Header/>
<Sidebar/>
<div id= "main-wrapper">
<Route path="/Shipped" component ={Shipped}/>
<Route path="/Warehouse" component ={Warehouse}/>
<Route path="/Assisted" component ={Assisted}/>
<Route path="/Profile" component ={Profile}/>
</div>
</Router>
</Provider>
);
}
export default App;
I think your making the code too overcomplicated, some steps I would introduce the following below.
Create a component called <Wrapper>, this should deal with the header responsibility. Just wrap this in every UI that you need it. You are building a variable which adds code duplication and could become a performance problem if you had 20 views which have no header..
<Wrapper />:
const Wrapper = ({ children }) => (
<>
<Head />
{children}
</>
);
On a side note, I think extracting data and jsx make for easier testing and if done correctly makes for easy code reviews!
This is what I would do with your routes:
routes.js:
// Import routes here...
const routes = [
{
path: "Login",
component: Login
},
{
path: "Reset",
component: Reset
},
{
path: "Confirm",
component: Confirm
},
{
path: "Signup",
component: Signup
},
{
path: "/Warehouse",
component: Warehouse
},
{
path: "/Assisted",
component: Assisted
},
{
path: "/Profile",
component: Profile
},
{
path: "/shipped",
component: Shipped,
exact: true
}
];
The benefit here is that you divide and separate out concerns in the app it makes debugging easier to deduce. This main component only cares about rendering routes, it also means your <App /> has only app required import not a block of route component imports.
Now your <App /> can be nice and small for example:
const App = () => (
<Provider {...{ store }}>
<Router>
<div id="main-wrapper">
{routes.map(route => (
<Route key={route.path} {...route} />
))}
</div>
</Router>
</Provider>
);
I hope this helps, let me know how you get on!
All i did was use a let statement to condition the header in the pages
import React, {Component} from 'react';
import {BrowserRouter as Router, Route, Switch} from 'react-router-dom';
import Head from './component/layout/Head';
import Shipped from './component/pages/Shipped';
import Warehouse from './component/pages/Warehouse';
import Assisted from './component/pages/Assisted';
import Login from './component/auth/Login'
import Profile from './component/pages/Profile';
import jwt_decode from 'jwt-decode';
import setAuthToken from './utils/setAuthToken';
import { Provider } from 'react-redux';
import PrivateRoute from './component/common/PrivateRoute';
import store from './store';
class App extends Component {
render(){
let HideHeader = window.location.pathname === '/Login' && '/Reset' && '/Confirm' && '/Signup' ? null : <Head/>
return (
<Provider store={store}>
<Router>
<div id= "main-wrapper">
{HideHeader}
<Route path="/Login" component={Login} />
<Route path="/Warehouse" component ={Warehouse}/>
<Route path="/Assisted" component ={Assisted}/>
<Route path="/Profile" component ={Profile}/>
<Route exact path="/shipped" component={Shipped} />
</div>
</Router>
</Provider>
);
}
}
export default App;
I have to combine use of Redux and React Router.
I tried react Router alone first and when I was clicking my images I was correctly redirected.
I followed redux tutorial and now when I click my images, I change the address (ex: http://localhost:3000/contact) but nothing displays as if the component was empty.
Root.js
import React from 'react';
import './index.css';
import PropTypes from 'prop-types'
import ReactDOM, { BrowserRouter as Router, Route, Link, Switch } from 'react-router-dom'
import App from './App'
import Users from './users'
import Book from './Book'
import Notfound from './notfound'
import { Provider } from 'react-redux';
import Store from './redux/Store/store'
import * as serviceWorker from './serviceWorker';
const Root = ({ store }) => (
<Provider store = { Store }>
<Router>
<div>
<Switch>
<Route exact path="/:filter?" component={App} />
<Route path="/users" component={Users} />
<Route path="/book" component={Book} />
<Route path='/manual' component={() => { window.location = 'https://------'; return null;} }/>
<Route path='/contact' component={() => { window.location = 'https://-------'; return null;} }/>
<Route component={Notfound} />
</Switch>
</div>
</Router>
</Provider>
)
Root.propTypes = {
store: PropTypes.object.isRequired
}
serviceWorker.unregister();
export default Root
index.js:
import React from 'react'
import { render } from 'react-dom'
import { createStore } from 'redux'
import myReducer from './redux/Reducers/myReducer'
import Root from './Root'
const store = createStore(myReducer)
render(<Root store={store} />, document.getElementById('root'))
App.js:
import React from 'react'
import { Route, Link, Redirect, withRouter, BrowserRouter as Router } from 'react-router-dom'
import logo from './images/logo.png';
import book from './images/book.png';
class App extends React.Component {
constructor() {
super();
this.state = {
date: new Date()
};
}
render() {
const { date } = this.state;
return (
<div>
<img src={logo} />
<img src={book} onClick={() => this.props.history.push('/book')}/>
<img src={call} onClick={() => this.props.history.push('/contact')}/>
</div>
)
}
}
export default App
Do you know what is wrong ?
A few things I noticed:
When using react router you shouldn't use window.location to redirect since this reloads the whole page. The <Redirect> component from react-router is a better choice here.
Also you shouldn't use the component prop on the <Route>-component for things that aren't actually components, as there's the render prop for that (more on that here).
Furthermore: <Route exact path="/:filter?" component={App} /> is not going to work since :filter? is looking for a variable and exact is looking for an exact match. Moreover you probably shouldn't put the flexible one first since it's going to match every route that you throw at it. So all the following routes are practically unreachable.