I have a problem with my react components.
Basically my interface should be an SPA, built with ReactJS.
During the implementation of the authentication with auth0-js I also implemented some routes.
The layout looks like this:
Whenever I click now on the "Recipes" link, it should redirect to the route "/recipes".
However, when I implement the route with <Route path="/recipes" component={Recipes} /> it only renders what is actually returned in the Recipes component. I know that this is correct from what react does.
Now, I want to keep the navigation bar but only want to exchange the component below, so I want to change what is below the navigation bar like I did in App.js.
How can I achieve this? Is something about the routes, or components not correct?
I do not want to re-render always everything. I also want to keep the style of the whole page. Is there a way to do this?
The whole code can be found here.
I agree with Jyutzio in that you need to move the Navigation component above the child routes to only change to content of the child routes.
In order to have the Navigation bar update with logged in / logged out state you may want to consider implementing redux. I have a project with nearly the exact requirements as yours - a navigation header that is static.
In my header I have import { connect } from 'react-redux';
At the bottom of the component I use connect before exporting:
function mapStateToProps(state) {
return { authenticated: state.auth.authenticated };
}
Header = connect(mapStateToProps)(Header);
export default Header;
Then this allows me to check the "authenticated" piece of state and render accordingly.
renderLogoutButton() {
if(this.props.authenticated) {
return(
<li><a onClick={...}>Logout</a></li>
);
} else {
return(
<li><a onClick={...}>Login</a></li>
);
}
}
You will need to setup a reducer, but there are many resources explaining redux setup.
The router (simplified) I have set up as follows:
import Admin from './index';
...
<BrowserRouter>
<Switch>
<Route exact path="/login" component={Login} />
<Route path="/" component={Admin} />
</Switch>
</BrowserRouter>
index:
import AdminRouter from './admin/admin_router';
...
<div>
<Menu />
<div>
<AdminRouter />
</div>
</div>
admin_router:
<div>
<Switch>
<Route exact path="/" component={Home} />
<Route exact path="/details" component={AdminDetails} />
<Route component={PageNotFound} />
</Switch>
</div>
If you place your Navigation component above the switch, it will solve your problem.
const Routes = () => (
<Router history={history} component={Home}>
<Route component={Navigation}/>
<Switch>
<Route exact path="/" render={props => <Home auth={auth} {...props} />} />
<Route path="/home" render={props => <Home auth={auth} {...props} />} />
<Route
path="/callback"
render={props => {
handleAuthentication(props);
return <Callback {...props} />;
}}
/>
<Route component={NotFound} />
</Switch>
</Router>
);
Related
I am facing little bit difficulty, I have to manage my dashboard using material-UI with other components
the process of application is that first I want to open login foam and then the dashboard and I am willing to change just the right-center part of the dashboard with the different component by selecting the listItem option
here is my Dashboard
here is all routes defined on my App.js
<Provider store={store}>
<BrowserRouter>
< Routes>
<Route exact path='/' element={<Login/>} />
<Route exact path='/dashboard' element={<Dashboard/>} />
<Route exact path='/product' element={<Product/>}/>
</Routes>
</BrowserRouter>
</Provider>
currently, the issue is that when I am going to login which is on my "/" route and after the authentication the app navigate on the dashboard but when I click my product tab so the dashboard is disappear there
here is my product page
i am willing to that all pages should to render just in text area where text is showing
I will make some assumptions before answering your question:
You want the Dashboard view to be always available
The Dashboard view's white screen should receive different content depending on the route that you're currently in
In your app you should have some sort of Layout which wraps the entire App. You are using react-router v6 so most probably the way to go it will be this:
<Provider store={store}>
<BrowserRouter>
<Routes>
<Route path="/" element={<Layout />}>
<Route exact path='/login' element={<Login/>} />
<Route exact path='/dashboard' element={<Dashboard/>} />
<Route exact path='/product' element={<Product/>}/>
</Route>
</Routes>
</BrowserRouter>
</Provider>
And in your Layout component, something like this:
import { Outlet } from 'react-router-dom';
const Layout = () => (
<main>
<Outlet />
</main>
);
You can check the react-router documentation for <Outlet />
Did it help?
EDIT: Forgot to say that yout <Layout /> view should have the Drawer that you're showing in your first screenshot, and the white space is where Outlet should be.
I have simple movie app with a home page and a watchlist page.
This is how I would like to structure it:
Home
/movie/id
Watchlist
watchlist/movie/id
I would like to access the movie/id from both the home page and the watchlist. Right now I can access it but the problem is when I open a movie when I'm on watchlist page it goes back to home and opens it from there, instead of staying on watchlist and opening it from there. I'm using React-Router v5.2. What should I write differently in the route? I tried /watchlist/movie/:id but then it didn't render the movie at all, only from Home.
function App() {
return (
<div className='App' style={{ overflowX: 'hidden' }}>
<GlobalStyles />
<Switch>
<Route exact path={['/movie/:id', '/']}>
<Home />
</Route>
<Route exact path={['/movie/:id', '/watchlist']}>
<Watchlist />
</Route>
</Switch>
</div>
);
}
export default App;
And that's the link for the movie page:
<Link to={`/movie/${id} `}>
</Link>
The issue is that the react router tries to match the first url and it is inside switch that will tell to render only one component , you need to remove switch , also donot forget to use BrowserRouter wrapper , as i donot see it in code
function App() {
return (
<div className='App' style={{ overflowX: 'hidden' }}>
<GlobalStyles />
<Route exact path={['/movie/:id', '/']}>
<Home />
</Route>
<Route exact path={['/movie/:id', '/watchlist']}>
<Watchlist />
</Route>
</div>
);
}
I rearranged my code the following way which fixed it. According to docs the more specific path like: /watchlist/movie/:id should come before the less specific path="/watchtlist".
<Switch>
<Route exact path='/watchlist/movie/:id'>
<MovieDetail pathId={pathId} />
</Route>
<Route path='/watchlist'>
<Watchlist />
</Route>
<Route path='/movie/:id'>
<MovieDetail pathId={pathId} />
</Route>
<Route exact path='/'>
<Home />
</Route>
</Switch>
I am building a React app that has a static marketing site and a dynamic app. I am using a combination of React Router and hooks to separate the two and ensure proper routing throughout.
To begin with, I want users who are logged in to be taken directly to the app when they hit the root ("/") and to the static/marketing site when not logged in. The main marketing site home page has a nav bar that allows users to access other routes such as "/about", whereas the app has a separate nav bar for app navigation.
The problem is, while the authentication based routing for the root route seems to be working, and I can navigate to other routes specified in my top-level file, the routes that are included within my static/marketing site are not accessible.
Top-level/index.js
const routing = (
<Provider store={store}>
<Router>
<NavWrapper />
{/* <Switch> */}
<Route exact path="/" component={AuthWrapper} />
<Route path="/signup" component={SignUp} />
<Route path="/login" component={Login} />
{/* </Switch> */}
</Router>
</Provider>
)
ReactDOM.render(routing, document.getElementById('root'));
AuthWrapper.js (here useAuth() is a React hook that evaluates global Redux isAuthenticated state)
const AuthWrapper = (props) => {
return useAuth() ? <App /> : <Website />
}
export default AuthWrapper;
website/index.js
export const Website = () => {
return (
<>
{/* <SiteNav /> */}
<Switch>
<Route exact path="/" component={LandingPage} />
<Route path="/about" component={AboutPage} />
<Route path="/how-it-works" component={HowItWorksPage} />
<Route path="/plans" component={PlansPage} />
<Route path="/press" component={PressPage} />
<Route path="/faq" component={FAQPage} />
<Route path="/legal" component={LegalPage} />
<Route path="/for-dieticians" component={DietitiansPage} />
<Route path="/for-trainers" component={PTsPage} />
</Switch>
</>
)
};
In my app, when I enter localhost:3000/ (unauthenticated) I am correctly taken to my home/landing page. However, if I try to use the navigation (or type in any subroutes) to access "/about" for example, I get a blank screen (other than the nav bar). In the React dev tools, the component isn't even rendering.
I think this is the issue:
<Route exact path="/" component={AuthWrapper} />
You want Authwrapper to be shown for about as well, right? But the above only matches "/" exactly.
You should enable the switch statement, but move the AuthWrapper Route to the bottom and then let it have this path: "/:rest*" (maybe "/*" works too, haven't used react-router in a while).
That way, it will use the Route if the first 2 don't match.
I wrote my application in a very modular way in the way that each package (section of the application) is a package and the only thing i'm returning from each package is a <Route to="/dest" component="something" />.
The problem that i'm having right now is that, this method of returning are not really working in and that's how i tested it:
The initial setup was something like this :
<Switch>
<Dashboard {...rest} />
<Users {...rest} />
<Quiz {...rest} />
</Switch>
And the Dashboard component is something like this :
...
return (
<Route exact path="/" render={ props => (
<Dashboard {...props} {...stuff} />
)}/>
)
and almost the same thing for User and Quiz components, which are directly being imported from their module packages.
when i run the application, i can access Dashboard & Users but Quiz is not being rendered.
if i change the order and put quiz on top of <Users /> it will work. which means it only can render one after first exact route.
but instead, if i take all those code and write the Routes in the switch itself without referencing to another component, it works like a charm.
<Switch>
<Route exact path="/" render={ props => (
<div>demo</div>
)}/>
<Route path="/dashboard" render={ props => (
<div>demo</div>
)}/>
<Route path="/users" render={ props => (
<Users />
)}/>
<Route path="/quiz" component="Users"/>
</Switch>
I've tried both component, and render in route, this one is just a sample
any suggestion on why is this happening ?
UPDATE 1
I haven't managed to figure out what the problem is and what's causing it, but i found a way around it by creating a component that returns a Switch and direct Routes as children. then i exported the Switch to my main app.
<Switch>
<Dashboard {...rest} />
<Users {...rest} />
<Quiz {...rest} />
</Switch>
This will not work because Switch expects Routes to be direct children. It cannot perform its logic on arbitrary wrapper components.
I not sure if that would work but you would have to directly export Route from the module:
Dashboard.js
export default (
<Route exact path="/" render={ props => (
<Dashboard {...props} />
)}/>
)
but when you do something like this:
export default (stuff) => (
<Route exact path="/" render={ props => (
<Dashboard {...props} {...stuff} />
)}/>
)
Notice that you are not exporting a Route but a functional component that renders Route.
I personally think that you should only export purely components to be rendered without Routes and leave that up to library consumer.
I have a React/Redux app and if a user hasn't finished the signup process if they log in again I want them to be redirected to the signup route for the step they are on no matter what route they try to go to. What's the best way for me to do this without having to make a custom route for every single one of my routes with that logic inside? Here is my basic router:
render() {
return (
<Router history={history}>
<Switch>
<HomeRoute exact path="/" publicComp={Start} privateComp={Rooms}/>
<Route path="/login" component={Login}/>
<Route path="/signup" component={SignUpMain}/>
</Switch>
</Router>
);
}
Ideally, something where I can just say "on all of these routes if signup isn't complete redirect to /signup". Is there a way to do this?
One way would be to replace your Route components with a higher order component that redirects to signup.
const RedirectRoute = ({ component: Component, ...rest }) => (
<Route
{...rest}
render={props =>
<Redirect
to="/signup"
/>
}
/>
);
If you add the higher order components to the bottom of the file with your Router above then you can just replace the Route components like so...
render() {
return (
<Router history={history}>
<Switch>
<RedirectRoute exact path="/" render={() => <HomeRoute exact path="/" publicComp={Start} privateComp={Rooms}/>}/>
<RedirectRoute path="/login" component={Login}/>
<Route path="/signup" component={SignUpMain}/>
</Switch>
</Router>
);
}
If you want to keep the higher order component in a seperate file then just import it like you would any other component.