React nested Routes implementation - reactjs

I am new to reactjs. i am trying to develop website who's home page or landing page has different design then signin user. after user logs in header changes and there is a sidebar. I have placed my signed routes inside signed in component but still its not working
<Switch>
<Route exact path="/" component={HomePage} />
<Route path="/Resident" component={customer} />
<Route path="/search" component={search} />
<Route component={EmptyPage} />
</Switch>
class customer extends Component {
constructor() {
super()
this.setLayout = this.setLayout.bind(this)
// Listen for changes to the current location.
history.listen((location, action) => {
// location is an object like window.location
//console.log('history', location.pathname, this.setLayout(location.pathname))
this.setLayout(location.pathname)
})
}
componentWillMount() {
this.setLayout(this.props.pathname)
}
setLayout(url) {
const emptyView1 = [
'/pages/error-page',
'/pages/create-account',
'/pages/login',
'/pages/under-maintenance',
];
let isEmptyView = indexOf(emptyView1, url) !== -1 ? true : false
let currentLayout = this.props.config.layout
if(isEmptyView && currentLayout !== 'empty-view-1') {
this.props.setConfig('layout', 'empty-view-1')
} else if(!isEmptyView && currentLayout !== 'default-sidebar-1') {
this.props.setConfig('layout', 'default-sidebar-1')
}
}
render() {
let {layout, background, navbar, logo, leftSidebar, topNavigation, collapsed} = this.props.config
// let {pathname} = this.props
let isEmptyView = layout === 'empty-view-1' ? true : false
return (
<ConnectedRouter history={history}>
<div
data-layout={layout}
data-background={background}
data-navbar={navbar}
data-logo={logo}
data-left-sidebar={leftSidebar}
data-top-navigation={topNavigation}
data-collapsed={collapsed}
>
<Shortcuts />
<Backdrops />
{!isEmptyView &&
<RightSidebar1 />
}
{!isEmptyView &&
<Navbar1 />
}
<div className="container-fluid">
<div className="row">
{!isEmptyView &&
<LeftSidebar1 />
}
<div className="col main">
<Switch>
<Route path="/dashboard" component={Dashboard} />
<Route path="/policies/index" component={Policies}/>
<Route path="/pages/create-account" component={CreateAccount} />
<Route path="/pages/empty-page" component={EmptyPage} />
<Route path="/pages/under-maintenance" component={UnderMaintenance} />
<Route path="/pages/error-page" component={ErrorPage} />
<Route path="/pages/user-profile" component={UserProfile} />
<Route path="/on-notice" component={OnNotice} />
<Route path="/profile" component={UserProfile} />
<Route path="/kyc-documents" component={KYCDocuments} />
<Route path="/booking" component={Booking} />
<Route path="/bookings" component={Bookings} />
<Route path="/pay-amount" component={Payment} />
<Route path="/security-deposit" component={Deposit} />
<Route path="/transactions" component={Transactions} />
<Route path="/notice-board" component={NoticeBoard} />
<Route path="/deals" component={Deals} />
<Route path="/checkin" component={Checkin} />
<Route path='/subscriptions' component={MySubscriptions} />
<Route path='/view-ticket' component={ViewTicket} />
<Route path="/new-ticket" component={NewTicket} />
<Route component={EmptyPage} />
</Switch>
</div>
</div>
</div>
</div>
</ConnectedRouter>
)
}
}
const mapStateToProps = (state, ownProps) => {
return {
pathname: state.router.location && state.router.location.pathname ? state.router.location.pathname : window.location.pathname,
config: state.config,
tickets : state.ticket
}
}
const mapDispatchToProps = dispatch => {
return {
setConfig: (key, value) => dispatch(setConfig(key, value))
}
}
export default connect(mapStateToProps, mapDispatchToProps)(customer)
I want to know how to do routing header and sidebar shouldn't be shown for non logged in user, there are few pages user can access without sign in
Above code which i have written is not routing.
Please guide me in right direction

router is old one method you can use ReactRouter (flowRouter kadira) package for easy routing
group.route('/', {
name: 'Routes.Task.List',
action () {
let props = {
content: (<Containers.List />),
title: 'title xyz',
pageTitle: 'title xyz',
};
mount(Wrapper, { props });
},
});
and now you can use this as flowRouter.path('Routes.Task.List')

Related

Nested route not rendering

will try to be brief.
Dashboard component is rendering, but while hitting localhost:3000/dashboard/shipments nothing is rendering.
Not versed in the react, not sure if render={({ location })(Line 1) is causing problem.
Tried placing components/simply h4 tag in Route (Line2) but nothing working.
Necessary imports are done.
App.js
const pages = [
{
pageLink: '/dashboard',
view: Dashboard,
displayName: 'Dashboard',
showInNavbar: true,
exact: false
},....more routes.
return(
<Router>
<Route render={({ location }) => (//---------->Line 1
<React.Fragment>
<Navbar />
<Switch location={location}>
{pages.map((page, index) => {
return (
<Route
exact={page.exact}
path={page.pageLink}
component={page.view}
key={index}
/>
)
})}
<Redirect to='/' />
</Switch>
</React.Fragment>
)}
/>
</Router>
)
dashboard.js
export default function Dashboard() {
const authedUser = useSelector(state => state.authedUser);
let { path } = useRouteMatch();
if (!authedUser.loggedIn) return <Redirect to='/login' />
return (
<React.Fragment>
<section id='dashboard-component'>
<Sidebar />
<Switch>
<Route exact path={path}>
<h2>Dashboard</h2>
</Route>
<Route exact path={`/${path}/shipments`}><h4>sdsd</h4></Route>//------>Line 2
</Switch>
</section>
</React.Fragment>
)
}
You have a extra / at the start of your nested Route
<Route exact path={`/${path}/shipments`}><h4>sdsd</h4></Route>
Now path already return /dashboard. Writing path={`/${path}/shipments`} would make the route path as path={'//dashboard/shipments'}
You need to specify your child route like
<Route exact path={`${path}/shipments`}><h4>sdsd</h4></Route>
Working demo

How to pass route props into my functional component

Link component
return (
<div key={driver.id}>
<Link to={"/drivers/" + driver.id}>
<OurStaffList driver={driver} />
</Link>
</div>
App.js
<Switch>
<Route exact path="/" component={HomePage} />
<Route path="/archived-routes" component={ArchivedRoutes} />
<Route path="/find-routes" component={FindRoutes} />
<Route path="/signup" component={SignUp} />
<Route path="/signin" component={SignIn} />
<Route path="/drivers/:driver_id" component={DriverProfile} />
</Switch>
And now here in the component where i need the route id, im getting 'error not recognized params...'
Can someone give me an idea how i can get the route props into the component so i can render the correct driver profile ?
const DriverProfile = ({ driver, getDrivers }) => {
useEffect(() => {
getDrivers();
// eslint-disable-next-line
}, []);
console.log();
return (
<div className="col s12">
<ul className="with-header">
{driver.drivers &&
driver.drivers.map(driver => {
return <DriverProfileList driver={driver} key={driver.id} />;
})}
</ul>
</div>
);
};
DriverProfile.propTypes = {
driver: PropTypes.object.isRequired
};
const mapStateToProps = (state, ownProps) => {
let id = ownProps.match.params.driver_id;
console.log(id);
return {
driver: state.driver
};
};
Answered by user6136000. Thanks
https://reacttraining.com/react-router/core/api/Hooks/useparams
So, in your DriverProfile function component:
let { driver_id } = useParams();
You can access all routing parameters in component by wrapping it with https://reacttraining.com/react-router/core/api/withRouter

Is it possible to match the # part for any route in React Router 5?

In my app, I'd like to match all routs that end with #something.
/map#login
/info#login
and
/map#register
/map/one#register
/info#register
/info/two#register
So I can show component as popup on top of the content. How this can be done?
I found a solution for this case. It was inspired from this question in stackOverflow. Using HashRoute wrapper for Route and showing component based on location.hash.
const HashRoute = ({ component: Component, hash, ...routeProps }) => (
<Route
{...routeProps}
component={({ location, ...props }) =>
location.hash === hash && <Component {...props} />
}
/>
);
export default class App extends Component {
constructor() {
super();
}
render() {
return (
<div className='App'>
<Router history={history}>
<HashRoute hash='#login'component={Login} />
<HashRoute hash='#register' component={Register} />
<Switch>
<Route exact path='/map' component={Map} />
<Route exact path='/info' component={Info} />
</Switch>
</Router>
</div>
);
}
}
Updating/improving from the other answer here. It would better to not use the component prop as it won't create new instance of the routed component each time the Route is rendered for any reason. The custom HashRoute component should return valid JSX, either a Route component or null.
Example:
const HashRoute = ({ hash, ...routeProps }) => {
const location = useLocation();
return location.hash === hash
? <Route {...routeProps} />
: null
};
...
<Router>
<HashRoute hash='#login' component={Login} />
<HashRoute
hash='#register'
render={props => <Register {...props} otherProp />}
/>
<HashRoute hash='#something'>
<Register otherProp />
</HashRoute>
<Switch>
<Route path='/map' component={Map} />
<Route path='/info' component={Info} />
</Switch>
</Router>

Getting Route Location outside of the Route

I am trying add a custom styling to the active route inside the navigation component inside the dashboardlayout, but I am not able to get the current route inside the current component.
const Index = props => {
return (
<BrowserRouter>
<DashboardLayout>
<Route exact path='/' component={Dashboard} />
<Route exact path='/earnings' component={Earnings} />
<Route exact path='/comms' component={Comms} />
<Route exact path='/rankings' component={Rankings} />
<Route exact path='/ratings' component={Ratings} />
<Route exact path='/ads' component={Ads} />
<Route exact path='/settings' component={Settings} />
<Route exact path='/ad/details' component={AdDetails} />
<Route exact path='/ad/submit-sample' component={SubmitSample} />
<Route exact path='/feedback' component={Feedback} />
</DashboardLayout>
</BrowserRouter>
);
};
export default Index;
I made a little component that looks like this:
import React from 'react';
import { Route, Link } from 'react-router-dom';
const Nav = ({
children,
to,
exact,
onClick,
className,
...rest
}) => (
<Route
path={to}
exact={exact}
children={({ match }) => (
<Link
// Assign class and active class name
className={match ? `${className} act-link` : className}
to={to}
replace={match && to === match.path}
onClick={(e) => {
// Avoid clicking the current route
if (!match || to !== match.path) {
onClick(e);
}
}}
{...rest}
>
{children}
</Link>
)}
/>
);
You can use it this way:
const NavList = ({
links,
toggleOpened,
}) => (
<ul className="main-menu">
{
links.map((link) => (
<li
key={link.name}
className={link.className}
>
<NavLink
className="icon-w"
to={link.url}
onClick={(e) => {
e.target.focus();
toggleOpened(false);
}}
>
<div className={`os-icon ${link.icon}`} />
</NavLink>
</li>
))
}
</ul>
);
Hope it helps

Nesting Switch components with global NoMatch component in react-router-v4

My app is currently separated into 3 parts:
Frontend
Administration
Error
Frontend, Administration and the Error component have their own styling.
The Frontend and Administration component are also have their own Switch component to navigate through them.
The problem I am facing is that I can't hit the NoMatch path without a Redirect component. But when I do this I lose the wrong path in the browser URL.
Is there a chance when the inner Switch component has no matching route that it keeps searching in its parent Switch component?
Then I would be able to hit the NoMatch route and also keep the wrong path in the URL.
Edit: I updated my answer below with the final solution that is working like intended.
const Frontend = (props) => {
const { match } = props;
return (<div>
<h1>Frontend</h1>
<p><Link to={match.path}>Home</Link></p>
<p><Link to={`${match.path}users`}>Users</Link></p>
<p><Link to="/admin">Admin</Link></p>
<p><Link to={`${match.path}not-found-page`}>404</Link></p>
<hr />
<Switch>
<Route exact path={match.path} component={Home} />
<Route path={`${match.path}users`} component={Users} />
{
// Workaround
}
<Redirect to="/error" />
</Switch>
</div>);
};
const Admin = (props) => {
const { match } = props;
return (<div>
<h1>Admin</h1>
<p><Link to={match.path}>Dashboard</Link></p>
<p><Link to={`${match.path}/users`}>Edit Users</Link></p>
<p><Link to="/">Frontend</Link></p>
<p><Link to={`${match.path}/not-found-page`}>404</Link></p>
<hr />
<Switch>
<Route exact path={match.path} component={Home} />
<Route path={`${match.path}/users`} component={Users} />
{
// Workaround
}
<Redirect to="/error" />
</Switch>
</div>);
};
const ErrorPage = () =>
<div>
<h1>404 not found</h1>
<p><Link to="/">Home</Link></p>
</div>;
const App = () => (
<div>
<AddressBar />
<Switch>
<Route path="/error" component={ErrorPage} />
<Route path="/admin" component={Admin} />
<Route path="/" component={Frontend} />
{
// this should render the error page
// instead of redirecting to /error
}
<Route component={ErrorPage} />
</Switch>
</div>
);
Here is the final solution for this kind of requirement.
To make it work we use the location's state property. On the redirect in the inner routes we set the state to error: true.
On the GlobalErrorSwitch we check the state and render the error component.
import React, { Component } from 'react';
import { Switch, Route, Redirect, Link } from 'react-router-dom';
const Home = () => <div><h1>Home</h1></div>;
const User = () => <div><h1>User</h1></div>;
const Error = () => <div><h1>Error</h1></div>
const Frontend = props => {
console.log('Frontend');
return (
<div>
<h2>Frontend</h2>
<p><Link to="/">Root</Link></p>
<p><Link to="/user">User</Link></p>
<p><Link to="/admin">Backend</Link></p>
<p><Link to="/the-route-is-swiggity-swoute">Swiggity swooty</Link></p>
<Switch>
<Route exact path='/' component={Home}/>
<Route path='/user' component={User}/>
<Redirect to={{
state: { error: true }
}} />
</Switch>
<footer>Bottom</footer>
</div>
);
}
const Backend = props => {
console.log('Backend');
return (
<div>
<h2>Backend</h2>
<p><Link to="/admin">Root</Link></p>
<p><Link to="/admin/user">User</Link></p>
<p><Link to="/">Frontend</Link></p>
<p><Link to="/admin/the-route-is-swiggity-swoute">Swiggity swooty</Link></p>
<Switch>
<Route exact path='/admin' component={Home}/>
<Route path='/admin/user' component={User}/>
<Redirect to={{
state: { error: true }
}} />
</Switch>
<footer>Bottom</footer>
</div>
);
}
class GlobalErrorSwitch extends Component {
previousLocation = this.props.location
componentWillUpdate(nextProps) {
const { location } = this.props;
if (nextProps.history.action !== 'POP'
&& (!location.state || !location.state.error)) {
this.previousLocation = this.props.location
};
}
render() {
const { location } = this.props;
const isError = !!(
location.state &&
location.state.error &&
this.previousLocation !== location // not initial render
)
return (
<div>
{
isError
? <Route component={Error} />
: <Switch location={isError ? this.previousLocation : location}>
<Route path="/admin" component={Backend} />
<Route path="/" component={Frontend} />
</Switch>}
</div>
)
}
}
class App extends Component {
render() {
return <Route component={GlobalErrorSwitch} />
}
}
export default App;
All child component routes are wrapped in the <Switch> the parent (the switch inside the app component) you don't actually the switch in the child components.
Simply remove child switch.component and let the 404 in the <App <Switch> catch any missing.

Resources