I have a Router File, where my Routes are nested under Index Component.
However, I want some other component, login which I don't want to Nest under any component but I want to use it to redirect to '/' home route.
If I use Div tags, then it is messing with my Template.
I am adding the Login component - route inside the Switch Tag.
If I don't do that I get React can only have one child error.
Does anyone know how to do a Nested Route and a Non-Nested One? Please Help.
This is my Router File.
import React, { Component } from 'react';
import './App.css';
import { Provider } from 'react-redux';
import store from './store/store';
import { Router, Route , Switch } from 'react-router-dom';
import Index from './actions/indexToggle/indexActions';
import FirstDashboard from './_layouts/views/firstDashboard';
import SecondDashboard from './_layouts/views/secondDashboard';
import ThirdDashboard from './_layouts/views/thirdDashboard';
import FourthDashboard from './_layouts/views/fourthDashboard';
import history from './history';
import FifthDashboard from './_layouts/views/fifthDashboard';
import Login from './_layouts/views/Login/login';
const Main = () => (
<Provider store={store}>
<Router history={history}>
<Switch>
<Index>
<Route exact path='/overview1' component={FirstDashboard} />
<Route exact path='/overview2' render={(props) => <SecondDashboard {...props} show="show" /> } />
<Route exact path='/overview3' component={ThirdDashboard} />
<Route exact path='/overview4' component={FourthDashboard} />
<Route exact path='/overview5' component={FifthDashboard} />
</Index>
<Route path='/login' component={Login} />
</Switch>
</Router>
</Provider>
)
export default Main;
Here what I've done. See DEMO.
I don't wanna be too confused because of this, so I choose a simple way.
routes.js
import Home from "./pages/Home";
import ComplexPath from "./pages/ComplexPath";
import Login from "./pages/Login";
export default [
{
path: "/",
component: Home,
withHeaderSidenav: true
},
{
path: "/yet/another/complex/path",
component: ComplexPath,
withHeaderSidenav: true
},
{
path: "/login",
component: Login,
withHeaderSidenav: false
}
];
Then, simply map the routes.
App.js
import React from "react";
import { Switch, Route } from "react-router-dom";
import BaseLayout from "./BaseLayout";
import routes from "./routes";
export default class extends React.Component {
state = {
withHeaderSidenav: true
};
showHeaderSidenav = (withHeaderSidenav = true) => {
this.setState({ withHeaderSidenav });
};
render() {
return (
<BaseLayout withHeaderSidenav={this.state.withHeaderSidenav}>
<Switch>
{routes.map(route => (
<Route
exact
key={route.path}
path={route.path}
render={() => (
<route.component
showHeaderSidenav={() =>
this.showHeaderSidenav(route.withHeaderSidenav)
}
/>
)}
/>
))}
</Switch>
</BaseLayout>
);
}
}
There will be a HOC for each page to handle layout changing. See pages/withBase.js in demo project.
Related
I am new to React and practicing with an online website for repairing appliances. I have used react-router and created all my routes in a separate file.
I have a problem though, I can open any link from the address bar like:
http://localhost:3000/<randomword>
I only want routes to be opened that I have declared in my routes component while if I type http://localhost:3000/something, I get an empty page with my header and footer in it.
here are my codes:
Index.js:
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from "react-router-dom";
import Routes from './Routes';
import './index.css';
const App = () => {
return(
<BrowserRouter>
<Routes />
</BrowserRouter>
)
}
ReactDOM.render(<App/>,document.getElementById('root'));
App.js:
import React, {Component} from 'react';
import { Route, BrowserRouter } from 'react-router-dom';
import Layout from './Containers/Layout';
import LandingPage from './Containers/Pages/LandingPage';
import About from './Containers/Pages/About';
import Cities from './Containers/Pages/Cities';
import Discount from './Containers/Pages/Discount';
class Routes extends Component {
render(){
return (
<div>
<Layout>
<BrowserRouter>
<Route path="/" render={props => <LandingPage {...props} />} exact component={LandingPage}/>
<Route path="/About" component={About}/>
<Route path="/Cities" component={Cities}/>
<Route path="/Discount" component={Discount}/>
</BrowserRouter>
</Layout>
</div>
);
}
};
export default Routes;
Layout.js:
import React, { Component } from 'react';
import Header from "./Layouts/Header";
import Footer from './Layouts/Footer';
import './Layout.css';
export default class Layout extends Component {
constructor(){
super();
this.state= {
}
}
render() {
return (
<div className="page-container">
<Header/>
<div className="content-wrap">
{this.props.children}
</div>
<Footer/>
</div>);
}
}
Can someone help me figure out how I should stop random random pages to be opened from addressbar?
Just want to start by saying I'm completely self-taught with React so I apologize if this answer is incorrect. However, in my experience with react-router I always have a Switch inside of my BrowserRouter. So your Routes class in app.js should something like this:
class Routes extends Component {
render(){
return (
<div>
<Layout>
<BrowserRouter>
<Switch>
<Route path="/" render={props => <LandingPage {...props} />} exact component={LandingPage}/>
<Route path="/About" component={About}/>
<Route path="/Cities" component={Cities}/>
<Route path="/Discount" component={Discount}/>
</Switch>
</BrowserRouter>
</Layout>
</div>
);
}
};
Just be sure you don't forget to update your imports to
import { Switch, Route, BrowserRouter } from 'react-router-dom';
import { Redirect } from "react-router-dom"
<Route path="/not-found" component={notFound-Component} />
<Redirect to="/not-found" />
This will always redirect you to 404 component if route is not present just make a 404 component and u should add the redirect at the end after all routes are defined
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 am learning redux with react and hit a mental roadblock, I have the following entry index.js:
import React from 'react';
import ReactDOM from 'react-dom';
import {BrowserRouter, Redirect, Route} from 'react-router-dom';
import {Provider} from 'react-redux';
import store from './store';
import Bootstrap from 'bootstrap/dist/css/bootstrap.css';
import Main from './components/front/Main';
import Login from './components/front/Login';
import Home from './components/front/Home';
import Register from './components/front/Register';
import Forgot from './components/front/Forgot';
import Verify from './components/front/Verify';
import Dashboard from './components/back/Dashboard';
import './css/app.css';
import Auth from './components/Auth';
const PrivateRoute = ({ component: Component, ...rest }) => (
<Route {...rest} render={props => (
Auth.isLogged ? ( //<-need to get props here
<Component {...props}/>
) : (
<Redirect to={{
pathname: '/',
state: { from: props.location }
}}/>
)
)}/>
)
const App = () => (<BrowserRouter>
<div>
{/* PUBLIC */}
<Route path={'/'} exact component={Home}/>
<Route path={'/login'} component={Login}/>
<Route path={'/register'} component={Register}/>
<Route path={'/forgot'} component={Forgot}/>
<Route path={'/verify'} component={Verify}/>
{/* PRIVATE */}
<PrivateRoute path="/dashboard" component={Dashboard}/>
</div>
</BrowserRouter>);
ReactDOM.render(<Provider store={store}><App/></Provider>, document.getElementById('root'));
Overall redux works, the only problem is in this file, as I am not exporting anything, I can't get connect to work.
Ideally Auth.isLogged should be either true or false based on isAuthenticated prop, but I can't get the value passed in any way to the entry index.js
import React from 'react';
import { connect } from 'react-redux';
#connect((store) => {
return {isAuthenticated: store.auth.isAuthenticated, authenticating: store.auth.authenticating};
})
export default class Auth extends React.Component {
//Can't get anything from here to index.js
}
Please any help would be greatly appreciated!
If I understand correctly, you’re trying to provide context of store.auth.isAuthenticated to PrivateRoute.
If you declare App in its' own file you can connect it to the store and then pass the value of isAutenticated to your PrivateRoute component
//App.js
import React, { Component } from 'react'
import { withRouter, Switch, Route } from 'react-router-dom'
import { connect } from 'react-redux'
import PrivateRoute from 'components/PrivateRoute'
#withRouter
#connect(store => ({
isAuthenticated: store.auth.isAuthenticated,
authenticating: store.auth.authenticating
}))
class App extends Component {
render() {
const { isAuthenticated } = this.props
return (
<span>
{/* PUBLIC */}
{ !isAuthenticated &&
<Switch>
<Route path={'/'} exact component={Home}/>
<Route path={'/login'} component={Login}/>
<Route path={'/register'} component={Register}/>
<Route path={'/forgot'} component={Forgot}/>
<Route path={'/verify'} component={Verify}/>
</Switch>
}
{/* PRIVATE */}
{ isAuthenticated &&
<PrivateRoute
isAuthenticated={isAuthenticated}
path="/dashboard"
component={Dashboard}
/>
}
</span>
)
}
}
export default App
For readability sake you could make this change in index.js
ReactDOM.render(
<Provider store={store}>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>,
document.getElementById('root')
)
You may or may not need to wrap connect(App) inside of withRouter, but the way I was handling my routing made this part necessary.
I have an app that I am creating and am wondering how you would insert variables into the <Route path={insert variable here} component={myProfile}> I am trying to create a myProfile page and I am trying to get it so when they click onto the link, it redirects them to http://mywebsite.com/userId but when I try to create a Route with a variable in the path argument, it does not return the component I am trying to render when on that path.
routes.js
import { Meteor } from "meteor/meteor"
import React from "react";
import { withRouter, Switch, BrowserRouter, Route, Redirect, Link } from "react-router-dom";
import Login from "../ui/authentication/Login";
import Signup from "../ui/authentication/Signup";
import Home from "../ui/Home";
import { SubjectRoutes } from "../ui/subjectRoutes/subjectRoutes";
import AddNote from "../ui/AddNote";
import myProfile from "../ui/myProfile";
import NotFound from "../ui/NotFound";
export default class Routes extends React.Component{
renderSubjectRoutes(subjects){
return subjects.map((subject) => {
return <Route key={subject.name} path={subject.path} component={subject.component}/>
})
}
render(){
return (
<div>
<BrowserRouter>
<Switch>
<Login path="/login" />
<Signup path="/signup" />
<Route path="/" component={Home} exact/>
{this.renderSubjectRoutes(SubjectRoutes)}
<AddNote path="/addNote"/>
<myProfile path={Meteor.userId()} /> //<-- Here
<NotFound />
</Switch>
</BrowserRouter>
</div>
)
}
}
Menu.js
import { Meteor } from "meteor/meteor"
import React from "react";
import { withRouter, Link } from "react-router-dom";
import { SubjectRoutes } from "./subjectRoutes/subjectRoutes";
import AddNote from "./AddNote";
class Menu extends React.Component{
renderMenu(items){
return items.map((item) => {
return <p key={item.name}><Link to={item.path}>{item.name}</Link></p>
})
}
render(){
return(
<div>
<h1>Menu</h1>
{this.renderMenu(SubjectRoutes)}
<p><Link to="/addNote">Add a Note</Link></p>
<p><Link to={Meteor.userId()}>My Profile</Link></p>
</div>
)
}
}
export default withRouter(Menu)
You are creating way more work for yourself, and this is the wrong way to add variables to route. What you're looking to do is add params to your route. In your case, you would want it to look something like this.
<Route path="/user/:userId" />
The : is what denotes that it is a parameter, ready to render a path based on the userId. So if you went to route /user/123 - it would be able to render user 123's data.
Here's some documentation to help you out.
https://reacttraining.com/react-router/web/example/url-params
I know this has been asked before but none of the answers applied to me so here goes. I have this basic route setup:
import React from 'react'
import { Router, Route, IndexRoute, browserHistory } from 'react-router'
import CoreLayout from 'layouts/CoreLayout/CoreLayout'
import AuthLayout from 'layouts/AuthLayout/AuthLayout'
import HomeView from 'views/Home/HomeView'
import AuthView from 'views/Auth/AuthView'
import SignupView from 'views/Signup/SignupView'
export default ( store ) => (
<Router history={browserHistory}>
<Route path='/' component={CoreLayout}>
<IndexRoute component={HomeView}/>
</Route>
<Route component={AuthLayout}>
<Route path="/signup" component={SignupView} />
<Route path="/auth" component={AuthView} />
</Route>
</Router>
)
I also have a button that, when pushed, should redirect to another page browserHistory.push( '/signup' ). When clicked, I can see the url updating in the browser but the component is not mounting. Any idea what am I doing wrong here?
As requested, here's my AuthLayout:
import React, { PropTypes } from 'react'
import 'styles/core.scss'
function AuthLayout( { children } ) {
return (
<div className='page-container'>
{children}
</div>
)
}
AuthLayout.propTypes = {
children: PropTypes.element
};
export default AuthLayout