below is my app.js code which will show the components based on the url. when user goes to /home, i need to perform some cookie operations. which i'm able to do. Since home component is required for more than one url, every url(/new,/dashboard) performs the cookie operation. Is it normal behavior ?
Below is my code, please let me know if this is react way to write it or not. I'm new to react js.
function App() {
return (
<div className="App">
<Router>
<Navbar />
<Switch>
<Route path="/" exact />
</Switch>
<Route path="/Home">
<Home />
<About />
</Route>
<Route path="/New">
<Home />
<New />
</Route>
<Route path="/Dashboard">
<Home />
<Dashboard />
</Route>
<Route path="/Run/:testid/">
<Run>
</Route>
</Router>
</div>
);
}
export default App;
below is my home component :
import { React, useEffect } from "react";
import { Button } from "./Button";
import { Link } from "react-router-dom";
import "./Navbar.css";
import "./Home.css";
import useQuery from "../hooks/useQuery";
function Home(props) {
const q = useQuery();
console.log(q.get("token"));
//save the token in cookie if url is /home, but since this home component is render for other urls like /new, /dashboard, it gets executed there as well.
return (
<main id="maincontent">
<div className="dashboard-btns">
<Link to="/dashboard" className="btn-mobile">
<Button id="dashboard" buttonStyle="btn--secondary">
Dashboard
</Button>
</Link>
<Link to="/new" className="btn-mobile">
<Button id="new" buttonStyle="btn--secondary">
New
</Button>
</Link>
<hr className="hr-line" />
</div>
</main>
);
}
export default Home;
In the < Home > component save the token in cookie only if url is /home, but since this home component is rendered for other urls like /new, /dashboard, it gets executed there as well. How do i make it get executed only for /home url
If you want the Home component to render on several routes then you can refactor your routes as such, and specify an array of paths for the route rendering Home. The Router component inclusively matches and render routes, in other words, it renders all matching routes.
function App() {
return (
<div className="App">
<Router>
<Navbar />
<Switch>
<Route path="/" exact /> // what is this for?
</Switch>
<Route path={["/Home", "/New", "/Dashboard"]}>
<Home />
</Route>
<Route path="/Home">
<About />
</Route>
<Route path="/New">
<New />
</Route>
<Route path="/Dashboard">
<Dashboard />
</Route>
<Route path="/Run/:testid/">
<Run>
</Route>
</Router>
</div>
);
}
Update
I'm doing some cookie storing and fetching operation in
component. But that should happen only on "/home" url and shouldn't
happen on "/new", "/dashboard" url. How do I do that?
You can check the current path match and issue a side-effect to do the cookie logic on only the "/home" path.
useRouteMatch
The useRouteMatch hook attempts to match the current URL in the same
way that a <Route> would. It’s mostly useful for getting access to the
match data without actually rendering a <Route>.
match will be null if path isn't a match, otherwise it will return a match object.
import { React, useEffect } from "react";
...
import { Link, useRouteMatch } from "react-router-dom";
...
import useQuery from "../hooks/useQuery";
function Home(props) {
const q = useQuery();
console.log(q.get("token"));
const homeMatch = useRouteMatch("/home");
useEffect(() => {
if (homeMatch) {
//save the token in cookie if url is /home and token defined
const token = q.get("token")
}
}, [homeMatch, q]);
return (
...
);
}
First thing is you can use "exact" to prevent that behaviour, Second you should not use two components inside route, what you can do is you can import Home inside New and Dashboard and use it there.
app.js
markdown.js
importing a component
using the imported component
Related
I was applying authenication in my project in React.js by using protectes routes. First i was using Redirect component from react-router-dom but then i have found out the changes they made in react-router-dom than i applied the navigate component.
import {BrowserRouter,Routes,Route,Navigate} from 'react-router-dom';
import './App.css';
import Navigation from './components/shared/Navigation/Navigation';
import Authenticate from './pages/Authenticate/Authenticate';
import Home from './pages/Home/Home';
import Login from './pages/Login/Login';
import Register from './pages/Register/Register';
const isAuth = true;
function App() {
return (
<div className="App">
<BrowserRouter>
<Navigation/>
<Routes>
<Route exact path='/' element={<Home/>}></Route>
{/* <Route exact path='/register' element={<Register/>}></Route>
<Route exact path='/login' element={<Login/>}></Route> */}
{/* <Route exact path='/authenticate' element={<Authenticate/>}></Route> */}
<GuestRoute exact path='/authenticate' element={<Authenticate/>}></GuestRoute>
</Routes>
</BrowserRouter>
</div>
);
}
const GuestRoute = ({children,...rest}) =>{
return(
<Route {...rest} render = {({location})=>{
return isAuth ?(
<Navigate to = '/rooms'state = {{from : location}} replace />
)
:(
children
)
}}></Route>
)
}
export default App;
This is my code after using the navigate component my screen not showing any thing there must be some kind of logical error in it. Kindly help me to resolve this error.
your app is showing nothing because the route /rooms does not match any routes in the <Routes /> component
I have a simple question. What is the best way to use a navbar with multiple components using react router? Just let me show the code so you can understand what I'm trying to say.
import React from "react";
import "./App.css";
import {
BrowserRouter as Router,
Switch,
Route,
Redirect
} from "react-router-dom";
import Auth from "./website/Auth/Auth";
import SocialMedia from "./website/SocialMedia/SocialMedia";
import SingleUser from "./website/SingleUser/SingleUser";
import Search from "./website/Search/Search";
import SinglePhoto from "./website/SinglePhoto/SinglePhoto";
import Navbar from "./components/Navbar/Navbar";
function App() {
const logIn = JSON.parse(localStorage.getItem("token"));
return (
<Router>
<Switch>
<Route exact path="/" component={Auth}>
{logIn ? <Redirect to={`/profile/${logIn.data.id}`} /> : <Auth />}
</Route>
<Navbar>
<Route exact path="/profile/:id" component={SingleUser} />
<Route exact path="/socialmedia" component={SocialMedia} />
<Route exact path="socialmedia/search" component={Search} />
<Route exact path="socialmedia/photo/:id" component={SinglePhoto} />
</Navbar>
</Switch>
</Router>
);
}
export default App;
So I have to reuse my Navbar component, and I tried to use <Navbar />, then the other routes below, but that wasn't working, and when I put <Navbar> </Navbar> that worked and the other components will appear, but is that the way I reuse my Navbar component?
Thanks for your time !!
import React from "react";
import "./App.css";
import {
BrowserRouter as Router,
Switch,
Route,
Redirect
} from "react-router-dom";
import Auth from "./website/Auth/Auth";
import SocialMedia from "./website/SocialMedia/SocialMedia";
import SingleUser from "./website/SingleUser/SingleUser";
import Search from "./website/Search/Search";
import SinglePhoto from "./website/SinglePhoto/SinglePhoto";
import Navbar from "./components/Navbar/Navbar";
function App() {
const logIn = JSON.parse(localStorage.getItem("token"));
return (
<Router>
<Switch>
<Route exact path="/" component={Auth}>
{logIn ? <Redirect to={`/profile/${logIn.data.id}`} /> : <Auth />}
</Route>
<Route Component={Navbar}>
<Route exact path="/profile/:id" component={SingleUser} />
<Route exact path="/socialmedia" component={SocialMedia} />
<Route exact path="socialmedia/search" component={Search} />
<Route exact path="socialmedia/photo/:id" component={SinglePhoto} />
</Route>
</Switch>
</Router>
);
}
export default App;
Try this!
If you want the Navbar to render only on certain routes then render it only on certain routes. Render the Navbar into a route outside the Switch and specify all the paths you want it to be rendered on in an array on the path prop.
Additional notes:
Within the Switch component, order and path specificity matter, reorder your routes to specify more specific paths before less specific paths. This allows you to not need to specify the exact prop for every route.
Don't specify both a component prop and render children on a single Route, see Route render methods. Just render the Redirect or Auth component as children.
Code:
function App() {
const logIn = JSON.parse(localStorage.getItem("token"));
return (
<Router>
<Route
path={["/profile", "/socialmedia"]}
component={Navbar}
/>
<Switch>
<Route path="/profile/:id" component={SingleUser} />
<Route path="socialmedia/photo/:id" component={SinglePhoto} />
<Route path="socialmedia/search" component={Search} />
<Route path="/socialmedia" component={SocialMedia} />
<Route path="/">
{logIn ? <Redirect to={`/profile/${logIn.data.id}`} /> : <Auth />}
</Route>
</Switch>
</Router>
);
}
I followed the Auth0 React Authentication guide written here:
https://auth0.com/blog/complete-guide-to-react-user-authentication
And implemented the ProtectedRoute component as outlined in the tutorial:
import React from "react";
import { Route } from "react-router-dom";
import { withAuthenticationRequired } from "#auth0/auth0-react";
import { Loading } from "../components/index";
const ProtectedRoute = ({ component, ...args }) => (
<Route
component={withAuthenticationRequired(component, {
onRedirecting: () => <Loading />,
})}
{...args}
/>
);
export default ProtectedRoute;
But now I am having an issue with the ProtectedRoute component that doesn't exist if I use withAuthenticationRequired directly in the export statement of the component that I am trying to protect. I have a web app that contains routes like the following:
<Router>
{isAuthenticated && <Header />}
<Switch>
<Route exact path='/'>
{isAuthenticated ? <Redirect to="/home" /> : <LandingPage />}
</Route>
<ProtectedRoute path='/home' component={Home}/>
<ProtectedRoute path='/events' component={Events}/>
<ProtectedRoute path='/dates' component={Dates}/>
</Switch>
</Router>
And my Home component contains something like the following:
function Home(){
return <div className="home-page">
<Sidebar />
<ProtectedRoute path={"/home/dogs"} component={Dogs}/>
<ProtectedRoute path={"/home/cats"} component={Cats}/>
</div>
}
export default Home;
The bug also happens when the Home component doesn't use ProtectedRoute like so:
function Home(){
return <div className="home-page">
<Sidebar />
<Route path={"/home/dogs"} component={Dogs}/>
<Route path={"/home/cats"} component={Cats}/>
</div>
}
export default Home;
I can't explain why it happens, but it prevents the state within the Sidebar component from changing the sidebar's appearance and rendered components.
Here is a link to a codesandbox on how the sidebar should work (no auth0).
https://codesandbox.io/s/react-routing-problem-2efic
When using ProtectedRoute as in the code above, the active class on the navbar links changes, but the rest of the content stays the same.
However, if I instead take the ProtectedRoute off of the Home component, but use withAuthenticationRequired on the export of the Home component, like so:
export default withAuthenticationRequired(Home, {
onRedirecting: () => (<div>Redirecting you to the login page...</div>)
});
and
<Route path='/home' component={Home}/> //instead of ProtectedRoute
Then everything works as it should.
My questions are:
Why is the ProtectedRoute component behaving differently from when withAuthenticationRequired is at the export level?
Do I need to protect routes that are nested within a protected route?
Thanks for any help!
I am new to React and getting familiarize with React Router. I divided the application into 2 main route since each use a different style: the Splash path is when the user first enter which contain the Splashscreen, Login and Register page; the Menu path is shown after the user is logined. Currently I am working on the Splash route but stumble on a few problem. The Splashscreen contain 1 button that go to the Login Screen. When I click on the button it worked fined, but if I refresh the login page, go back to the Spashscreen and forward, or manually enter the address, the page turn out blank. I tried using HashRouter and it worked, but some suggested that it should only be used on Dev server and not production. I don't use Webpack so I cannot make historyApiFallback: true and the application is running on localhost.
Below are my current code:
App.js:
import React from 'react';
import './App.css';
import SplashTemplate from './component/Template/SplashTemplate';
import {
BrowserRouter as Router,
Switch,
Route
} from "react-router-dom";
function App() {
return (
<Router>
<div className="App">
<Switch>
<Route path="/" exact={true}>
<SplashTemplate/>
</Route>
</Switch>
</div>
</Router>
);
}
export default App;
SplashTemplate.js:
import React from 'react';
import Splash from '../Splash/Splash';
import LoginForm from '../LoginForm/LoginForm';
import RegistrationForm from '../RegistrationForm/RegistrationForm';
import '../Template/SplashTemplate.css';
import { BrowserRouter, Route, Switch } from "react-router-dom";
function SplashTemplate() {
return(
<div className="background">
<BrowserRouter>
<Switch>
<Route exact path="/" component={Splash} />
<Route path="/login" component={LoginForm} />
<Route path="/register" component={RegistrationForm}/>
</Switch>
</BrowserRouter>
</div>
);
}
export default SplashTemplate;
Splash.js:
import React from 'react';
import {
BrowserRouter as Router,
Link
} from "react-router-dom";
function Splash() {
return(
<div className="container">
<Link to="/login">
<button className="splashButton">Login</button>
</Link>
</div>
);
}
export default Splash;
Anyone can suggest a solution? I have try the above mention but still not the answer I am looking for.
Update
Thanks to Danilo Venticinque answer I have reformatted the App.js file to:
function App() {
return (
<Router>
<div className="App">
<Switch>
<SplashTemplate>
<Route exact path="/" component={Splash}/>
<Route path="/login" component={LoginForm}/>
<Route path="/register" component={RegistrationForm}/>
</SplashTemplate>
<MainTemplate>
<Route path="/mainmenu" component={MainMenu}/>
</MainTemplate>
</Switch>
</div>
</Router>
);
}
And changed the SplashTemplate.js to:
class SplashTemplate extends Component {
render(){
return(
<div className="background">{this.props.children}</div>
);
};
}
It seem to work for the Splash path but now the problem show up in the Menu path where if the route is input manually (http://localhost:3000/mainmenu) the template for the Menu did not show up but instead the Splash template did. What am I doing wrong here?
Your problem is in the App.js routing. It's rendering the SplashTemplate component (which contains the other routes) only when the exact path is /. So, if you launch the page with /login, SplashTemplate doesn't get rendered (actually, nothing does) and there's no router to serve your other routes.
I would suggest moving the routes into a single component or changing the App.js routing logic so that it would still display SplashTemplate for /login and other desired routes.
So after digging around and following both React Router V4 Routers with Master Pages / Templates and React Router v5.0 Nested Routes I was able to come up with a solution. First, move all the Routing to a seperate file call Route.js and import it to App.js. Since we need to seperate the two path we will put the routing in 2 different functions and call them in a main function like below:
Route.js
...
function LayoutRoute() {
return (
<Switch>
<Route path="/splash" component={SplashLayout} />
<Route path="/main" component={MainLayout} />
<Route path="/" component={NotFound} />
</Switch>
);
}
function SplashLayout() {
return (
<SplashTemplate>
<Route path="/splash/splash" exact component={Splash} />
<Route path="/splash/login" exact component={LoginForm} />
<Route path="/splash/register" exact component={RegistrationForm} />
<Redirect from="/splash" to="/splash/splash" exact />
<Route />
</SplashTemplate>
);
}
function MainLayout() {
return (
<MainTemplate>
<Route path="/main/menu" exact component={MainMenu} />
<Redirect from="/main" to="/main/menu" exact />
<Route />
</MainTemplate>
);
}
const NotFound = () => <h1>Not Found</h1>;
export default LayoutRoute;
The App.js can just call Route:
function App() {
return (
<Router>
<LayoutRoute></LayoutRoute>
</Router>
);
}
And the Template file:
SplashTemplate.js
class SplashTemplate extends Component {
render(){
return(
<div className="background">{this.props.children}</div>
);
};
}
This can help achive seperated Layout for each path of the website/app needed and make sure the page is rendered when entered manually or refresh.
I am new to the react-redux. Here I am using the following thing for showing the 404 not found if the given route does not matches.
now, In this
My App.js
class App extends React.Component {
render() {
return (
<Provider store={store}>
<div className="container-fluid">
<Header />
<Main />
</div>
</Provider>
)
}
}
My Main.js
render() {
return (
<div>
<Router history={history}>
<div>
{this.props.isFetching && <Loading />}
<Switch>
<PrivateRoute exact path="/" component={LandingScreen} />
<PrivateRoute exact path="/quiz-setup" component={QuizSetupMain} />
<PrivateRoute exact path="/quiz-questions" component={FetchedQuestionComponent} />
<Route exact path="/login" component={LoginComponent} />
<Route exact path="/*" component={NotFound} something="foo" />
</Switch>
</div>
</Router>
</div>
)
}
}
NotFound.js
import React from 'react';
export default class NotFound extends React.Component {
render() {
return (
<h1>Something Went Wrong</h1>
);
}
}
Now , here when user hits any route which is not present then it shows that 404 not found, but it also shows the header part as well. I know that , its because I have rendered both header and main in the app.js file, and not found is in the main, but is there any way to not show that header , if the route is not matched . thanks
You can add function, which returns Component after Header.
for example:
const withHeader = (Component) => {
return class withHeaderComponent extends React.Component{ render() { return (<div><Header /><Component /></div>)}}
}
after creating this function, you can use it like,
<Route exact path="/login" component={withHeader(LoginComponent)} />.
So you are able to add header for Routes you want.
<Route component={NotFound}/>
Now your 404 will be without Header !
Let me know if you face difficulties.
You can use the component of dynamic components.
The idea is, every route path that is called, navigates through a common component which invokes suitable behaviour based on the component called. For example -
<PrivateRoute exact path="/" component={CustomComponent} />
and then pass props accordingly to determine, which screen has to render the header component.
So, essentially, your code will look something like this -
class App extends React.Component {
render() {
return (
<Provider store={store}>
<div className="container-fluid">
<Main />
</div>
</Provider>
)
}
}
and the <Header/> component will be called in custom component based on appropriate conditions that you put forward
Hope it helps :)
You can also use a wildcard to redirect people to not found page the route is not accessible.
import React from 'react';
import { Switch } from 'react-router';
import { BrowserRouter , Route ) from 'react-router-dom;
import NotFound from './NotFound';
const routes = (
<BrowserRouter>
<Switch>
<Route path="*" component={NotFound}/>
</Switch>
</BrowserRouter>
)