React-BreadCrumbs does not pick up variable from method - javascript

I have a multi-page web application running with reactjs.
I'm trying to define a custom react-breadcrumb for a specific page
which involves extracting a value and using that in the breadcrumb
Running the code with the below, I can see that console picks up jobName
But if I look at the breadcrumbs, I'm stuck with
home > templates > Missing name prop from Route
I don't quite understand why the variable isn't being picked up for the router. If I just hard code it in, it will work. Any advice?
getTemplateJobName(templateId,dateChosen){
doGetJobById({jobId: templateId,reconDate: dateChosen}).then(
({body: template})=>{
let {jobName: jobName}=template;
console.log(jobName);
return jobName;
});
},
render(){
return (
<div>
<Router history={browserHistory}>
<Route name='home' path={'/'+contextName}>
<IndexRoute component={LandingPage}/>
<Route name='templates' path='templates'>
<IndexRoute component={JobPage}/>
<Route path=':reconDate&:templateId' component={JobDetailPage} staticName={true} getDisplayName={(params) => this.getTemplateJobName(params.templateId,params.reconDate)}/>
</Route>
<Route name='report' path='report' component={ReportPanel}/>
</Route>
<Route path='*' component={NotFoundPage}/>
</Router>

Try this please;
export default App extends React.Component {
constructor(props) {
super(props);
this.state = {
DisplayName: ''
};
}
getTemplateJobName(templateId,dateChosen) {
doGetJobById({jobId: templateId,reconDate: dateChosen}).then(
({body: template})=>{
let {jobName: jobName}=template;
console.log(jobName);
// return jobName;
this.setState({ DisplayName: jobName });
}
);
}
getDisplayName(params) {
this.getTemplateJobName(params.templateId,params.reconDate);
return this.state.DisplayName;
}
render() {
return
(<div>
<Router history={browserHistory}>
<Route name='home' path={'/' + contextName}>
<IndexRoute component={LandingPage}/>
<Route name='templates' path='templates'>
<IndexRoute component={JobPage}/>
<Route path=':reconDate&:templateId' component={JobDetailPage} staticName={true} getDisplayName={ this.getDisplayName.bind(this) }/>
</Route>
<Route name='report' path='report' component={ReportPanel}/>
</Route>
<Route path='*' component={NotFoundPage}/>
</Router>
</div>)
}
}

Related

How to protect routes in React 18?

I have an admin dashboard and want that only admins are able to see the pages. So I set a condition into my router. When I am logged in, I am able to open every page, but I get the warning:
No routes matched location “/pagename”
Navbar and Sidebar staying in the same position, so that every page opens in a div named ContentWrapper.
How can I get rid of this warning?
Code:
const admin = useAppSelector((state)=>state.auth.user?.isAdmin);
return (
<Container>
<Router>
<Routes>
<Route path="/" element={<Login/>}/>
</Routes>
{admin &&
<>
<Navbar/>
<Wrapper>
<Sidebar/>
<ContentWrapper>
<Routes>
<Route path="/home" element={<Home/>}/>
<Route path="/sales" element={<Sales/>}/>
<Route path="/analytics" element={<Analytics/>}/>
<Route path="/transactions" element={<Transactions/>}/>
<Route path="/reports" element={<Reports/>}/>
<Route path="/mail" element={<Mail/>}/>
<Route path="/feedback" element={<Feedback/>}/>
<Route path="/messages" element={<Messages/>}/>
<Route path="/manage" element={<Manage/>}/>
<Route path="/user" element={<User/>}/>
<Route path="/products" element={<Products/>}/>
<Route path="/productlistChild" element={<ProductlistChild/>}/>
<Route path="/productlistWomen" element={<ProductlistWomen/>}/>
<Route path="/productlistMen" element={<ProductlisttMen/>}/>
<Route path="/productlistSportschuhe" element={<ProductlistSportschuhe/>}/>
<Route path="/productlistSneaker" element={<ProductlistSneaker/>}/>
<Route path="/cardImages" element={<CardImages/>}/>
<Route path="/sneakerImage" element={<SneakerImage/>}/>
<Route path="/sliderImage" element={<SliderImages/>}/>
<Route path="/newsletterBackground" element={<NewsletterBackground/>}/>
<Route path="/descriptionItems" element={<DescriptionItems/>}/>
</Routes>
</ContentWrapper>
</Wrapper>
</>
}
</Router>
</Container>
);
}
Did something similar recently
You can create a PrivateRoute Component
import { Navigate, Outlet } from 'react-router-dom';
const PrivateRouteAdmin = ({ isLoggedIn, role }) => {
return isLoggedIn && role === 'Admin' ? <Outlet /> : <Navigate to="/login" />;
};
export default PrivateRouteAdmin;
and then you can use it in your App.js like this
<Route element={<PrivateRouteAdmin isLoggedIn={isLoggedIn} role={user?.data?.role} />}>
<Route element={<DashboardWrapper />}>
{PublicRoutesAdmin.map((route, index) => {
return <Route key={index} path={route.path} element={<route.component />} />;
})}
</Route>
</Route>
PublicRoutesAdmin.map has just all the routes in a separate file, nothing fancy.
You can have other public routes pout of the private route component
I would resolve this by creating two groups of routes: Private and Public:
const PublicRoutes = () => (
<Fragment>
<Route path="/public/a"><ComponentA /></Route>
<Route path="/public/b"><ComponentB /></Route>
</Fragment>
)
const PrivateRoutes = () => (
<Fragment>
<Route path="/private/a"><PrivComponentA /></Route>
<Route path="/private/b"><PrivComponentB /></Route>
</Fragment>
)
And then have a RootRouter component which conditionally renders either the public or the private routes based on a condition:
const RootRouter = () => {
return (
<Router>
<Routes>
{admin ?
<Fragment>
<PublicRoutes />
<PrivateRoutes />
</Fragment> :
<PublicRoutes />
}
</Routes>
</Router>
)
}
This way, you are rendering the PublicRoutes AND the PrivateRoutes for the admin, but only the PublicRoutes for non-admin users.

How to make home path display from sub-route using React Router Dom?

www.mysite.com
www.mysite.com/
www.mysite.com/1
I want my site to display the same page for each of the above routes. Currently it displays nothing for www.mysite.com and www.mysite.com/
function App() {
return (
<Router>
<Routes>
<Route path="/" element={<Products />}>
<Route path="/:id" element={<ProductDisplay />} />
</Route>
</Routes>
</Router>
);
}
Products component
function Products() {
return (
<div className="products">
<Outlet />
</div>
);
}
export default Products;
If you want the ProductDisplay component to render on "/" as well as "/:id" then render an additional index route that will match with the parent route path.
Example:
function App() {
return (
<Router>
<Routes>
<Route path="/" element={<Products />}>
<Route index element={<ProductDisplay />} /> // <-- renders on "/"
<Route path="/:id" element={<ProductDisplay />} />
</Route>
</Routes>
</Router>
);
}
See Index Routes for more details.

Can't pass a function to a component via <Route />

setErm is a function and is undefined in Erm component. Although the App component receives it. If I pass anything like something='foo' the ERM component get's it but not setErm={props.setErm}
const App = props => {
console.log("props in App", props);
return (
<Router>
<div>
<Switch>
<Route exact path="/" component={Home} />
<Route
path="/erm"
render={props => <Erm {...props} setErm={props.setErm} />}
/>
<Route exact path="/:weekId" component={Week} />
<Route exact path="/:weekId/:dayId" component={Day} />
</Switch>
</div>
</Router>
);
};
The problem in your code is that in your Erm component props here refer to the Route component props not App props so you can change your code to use the props of App to something like this:
const App = props => {
console.log('props in App', props);
const appProps = props; // add this line to refer to App props
return (
<Router>
<div>
<Switch>
<Route exact path="/" component={Home} />
<Route
path="/erm"
render={props => <Erm {...props} setErm={appProps.setErm} />}
/>
<Route exact path="/:weekId" component={Week} />
<Route exact path="/:weekId/:dayId" component={Day} />
</Switch>
</div>
</Router>
);
};
Or you can use destructuring:
const App = ({ setErm }) => {
console.log('props in App', props);
return (
<Router>
<div>
<Switch>
<Route exact path="/" component={Home} />
<Route
path="/erm"
render={props => <Erm {...props} setErm={setErm} />}
/>
<Route exact path="/:weekId" component={Week} />
<Route exact path="/:weekId/:dayId" component={Day} />
</Switch>
</div>
</Router>
);
};
As you can see you now able to use the top props of App component

React-router browserHistory.push doesn't redirect

Trying to use browserHistory.push method to change my route programmatically.
It will change the route (per browser address bar) but doesn't update the view.
Here's my code
App.jsx
const AppStart = React.createClass({
render: function() {
return (
<MuiThemeProvider>
<Router history={hashHistory}>
<Route path="/" component={Main}>
<Route path="experiences" component={Experiences} />
<Route path="people" component={Profiles} />
<Route path="login" component={Login} />
<IndexRoute component={Home}/>
</Route>
</Router>
</MuiThemeProvider>
);
}
});
ReactDOM.render(
<AppStart />,
document.getElementById('app')
);
Component:
handleLoginRedirect(e) {
browserHistory.push('/experiences');
},
render() {
return (
<div className='row'>
<div className='col-sm-10 col-sm-offset-1'>
<form role='form'>
<RaisedButton label="Redirect" onClick={this.handleLoginRedirect} />
</form>
</div>
</div>
);
Your router configuration uses hashHistory while you're pushing onto browserHistory.
It's easy to miss something like this and it's understandable.
Replace hashHistory with browserHistory in your Router like so:
<Router history={browserHistory}>
Full Snippet:
const AppStart = React.createClass({
render: function() {
return (
<MuiThemeProvider>
<Router history={browserHistory}>
<Route path="/" component={Main}>
<Route path="experiences" component={Experiences} />
<Route path="people" component={Profiles} />
<Route path="login" component={Login} />
<IndexRoute component={Home}/>
</Route>
</Router>
</MuiThemeProvider>
);
}
});
If you're using the newest react-router api you'll need to use:
this.props.history.push('/path/goes/here');
You may need to bind this to your function when accessing this.props (note: may):
onClick={this.handleLoginRedirect.bind(this)}
Please refer to the following question for all the information on this topic:
Programmatically navigate using react router

Redirecting user based on state in React

Right now, my router looks like this:
<Router history={browserHistory}>
<Route component={Provider}>
<Route path="/" component={AppPage}>
<Route path="login" component={LoginPage}/>
<Route component={LoggedinPage}>
<Route path="onboarding" component={OnboardingPage}/>
<Route component={OnboardedPage}>
<IndexRoute component={HomePage}/>
<Route path="settings" component={SettingsPage}/>
</Route>
</Route>
</Route>
</Route>
</Router>
LoggedinPage redirects to /login if the user isn't logged in and OnboardedPage redirects to /onboarding if the user hasn't completed the onboarding flow (choosing username, etc). However, I think more of these conditional redirects may be needed in the future. What's the best way to handle these conditional redirects? Is it possible to have a single component that handles all the redirects?
<Route>s accept an onEnter hook that is called when the route matches. A hook would look something like this:
function requireAuth(nextState, replace) {
if (!loggedIn()) {
replace({ pathname: 'login' });
}
}
Then use it like so:
<Route path="/" component={AppPage}>
<Route path="home" component={HomePage} onEnter={requireAuth}/>
<Route path="login" component={LoginPage}/>
</Route>
A more composable example, that lets you combine multiple checks:
function checkAuth() {
if (!loggedIn()) {
return { pathname: 'login' };
}
}
function checkOnboarding() {
if (!completedOnboarding()) {
return { pathname: 'onboarding' };
}
}
function redirect(...checks) {
return function(nextState, replace) {
let result;
checks.some(check => {
result = check();
return !!result;
});
result && replace(result);
};
}
Then combine away!
<Route path="/" component={AppPage}>
<Route path="home" component={HomePage}
onEnter={redirect(checkAuth, checkOnboarding)}/>
<Route path="login" component={LoginPage}/>
<Route path="onboarding" component={OnboardingPage}
onEnter={redirect(checkAuth)}/>
</Route>
You could have a function that checks the if the user is logged in, and just import that:
import {browserLocation} from './browser-location'
export default function checkLoggedIn() {
if (localStorage.jwt === null)
browserLocation.pushState('/login')
}

Categories

Resources