React -router doesn't add component to the dom - reactjs

I have Quotes component which contains list of quotes. When I click individual list element, react router changes the url dynamically and opens it in full page which is Full_Screen_Quotes then again inside the Full_Screen_Quotes I want to add Comments section on button click with the help of react router, but it does not work for the reason I do not know. What might be the reason?
import { useParams } from "react-router-dom/cjs/react-router-dom.min"
import Comments from "./Comments"
import classes from '../css/Full_Screen_Quote.module.css'
import db from "./db"
import { useState } from "react"
import { Router,Route } from "react-router-dom/cjs/react-router-dom.min"
import { Link } from "react-router-dom"
import { Switch } from "react-router-dom/cjs/react-router-dom.min"
const Full_Screen_Quotes = ()=>{
const params = useParams()
return(
<>
<div className={classes.quote}>
<h1>{params.quoteId} </h1>
<h4>{params.authorId}</h4>
<Link to = {`/Allquotes/${params.authorId}/${params.quoteId}/comments`}> // Link that adds comment section
<button>ADD</button>
</Link>
</div>
<Route path ={`/Allquotes/${params.authorId}/${params.quoteId}/comments` } exact > //Comment section path
<Comments></Comments>
</Route>
</>
)
}
export default Full_Screen_Quotes
App js
import logo from './logo.svg';
import './App.css';
import {Route} from 'react-router-dom'
import {Switch} from 'react-router-dom'
import {Link} from'react-router-dom'
import MainHeader from '../src/components/MainHeader'
import Quotes from '../src/components/Quotes'
import AddQuotes from './components/AddQuotes';
import Welcome from './components/Welcome'
import {useParams} from 'react-router-dom'
import ListElement from './components/ListElement';
import Full_Screen_Quote from '../src/components/Full_Screen_Quote'
import {Redirect} from 'react-router-dom'
import Home from '../src/components/Home'
import NotFound from './NotFound';
import {useState,useCallback,useMemo} from 'react'
import { Prompt } from 'react-router-dom/cjs/react-router-dom.min'
import Comments from './components/Comments';
function App() {
const [is_focused,set_is_focused] = useState(false)
return (
<div>
<Switch>
<Route path ='/Welcome/' exact>
<Welcome/>
</Route>
<Route path ='/Allquotes/' exact>
<Quotes />
</Route>
<Route path ='/Addquote/' exact>
<AddQuotes set_is_focused = {set_is_focused} is_focused={is_focused} />
</Route>
<Route path ='/Allquotes/:authorId/:quoteId' exact>
<Full_Screen_Quote />
</Route>
</Switch>
</div>
)
}
export default App;
Comments js
import { useState } from "react"
import db from '../components/db'
import { useRef } from "react"
const Comments = (props)=>{
return (
<div style={{display:'flex',justifyContent:'center'}}>
<div> <textarea style={{transition:'1s all'}}></textarea> </div>
</div>
)}
export default Comments

Your root router/Switch is exactly matching URL paths, and in the case of rendering the Full_Screen_Quote component it only exactly matches up to '/Allquotes/:authorId/:quoteId'
<Route path ='/Allquotes/:authorId/:quoteId' exact>
<Full_Screen_Quote />
</Route>
As soon as the path becomes "/Allquotes/someAuthorId/someQuoteId}/comments" it no longer matches exactly and your Full_Screen_Quote component is unmounted, thus unmounting the nested Route you want to render for the Comments component.
In 99.99% for use cases there's really no need to use the exact prop in conjunction with the Switch since you can order the rendered routes in inverse order of path specificity so matching can work properly. Using the exact prop also necessarily precludes the further matching of any nested routes.
You've a couple options:
Order the routes in the Switch in descending path specificity order and remove the exact prop. This allows the nested route in Full_Screen_Quote to be eventually matched and rendered.
<Switch>
<Route path='/Welcome/'>
<Welcome />
</Route>
<Route path='/Allquotes/:authorId/:quoteId'>
<Full_Screen_Quote />
</Route>
<Route path='/Allquotes/'>
<Quotes />
</Route>
<Route path='/Addquote/'>
<AddQuotes
set_is_focused={set_is_focused}
is_focused={is_focused}
/>
</Route>
</Switch>
...
const Full_Screen_Quotes = () => {
const { path, url } = useRouteMatch();
const params = useParams();
return (
<>
<div className={classes.quote}>
<h1>{params.quoteId} </h1>
<h4>{params.authorId}</h4>
<Link to={`/${url}/comments`}>
<button>ADD</button>
</Link>
</div>
<Route path={`${path}/comments`}>
<Comments />
</Route>
</>
);
};
Move the nested route out to the main router/Switch and order the routes in descending path specificity order and remove the exact prop.
<Switch>
<Route path='/Welcome/'>
<Welcome />
</Route>
<Route path='/Allquotes/:authorId/:quoteId/comments'>
<Comments />
</Route>
<Route path='/Allquotes/:authorId/:quoteId'>
<Full_Screen_Quote />
</Route>
<Route path='/Allquotes/'>
<Quotes />
</Route>
<Route path='/Addquote/'>
<AddQuotes
set_is_focused={set_is_focused}
is_focused={is_focused}
/>
</Route>
</Switch>
...
const Full_Screen_Quotes = () => {
const { url } = useRouteMatch();
const params = useParams();
return (
<div className={classes.quote}>
<h1>{params.quoteId} </h1>
<h4>{params.authorId}</h4>
<Link to={`/${url}/comments`}>
<button>ADD</button>
</Link>
</div>
);
};

wrap the app.js in a router
import {BrowserRouter as Router} from 'react-router-dom'
then
<Router>
<Switch>
<Route path ='/Welcome/' exact>
<Welcome/>
</Route>
<Route path ='/Allquotes/' exact>
<Quotes />
</Route>
<Route path ='/Addquote/' exact>
<AddQuotes set_is_focused = {set_is_focused} is_focused={is_focused} />
</Route>
<Route path ='/Allquotes/:authorId/:quoteId' exact>
<Full_Screen_Quote />
</Route>
</Switch>
</Router>

Related

Error: [AdminRoute] is not a <Route> component. All component children of <Routes> must be a <Route> or <React.Fragment>

I want authenticated routes if user is not logged in the page should not be accessible like if someone enters in the url localhost.../admin/dashboard he should not be able to navigate instead he should be taken to signin page if not logged in.
I'm using react-router v6 and creating private routes for my application.
AdminRoute.js File Code is below
import React from "react";
import { Route, Navigate} from 'react-router-dom';
import { isAuthenticated } from "../helper/auth";
//props component is assigned to Component
//...rest spreading props property but reassigning it to a variable called rest
const AdminRoute = ({ component: Component, ...rest }) => {
return (
<Route
{...rest}
render={(props) =>
isAuthenticated() && isAuthenticated().role === 1 ? (
<Component {...props} />
) : (
<Navigate to = '/signin' />
)
}
/>
)
};
export default AdminRoute;
App.js File Code is below
import React from 'react';
import {BrowserRouter, Route, Routes} from 'react-router-dom';
import Header from './Header';
import Home from './Home';
import Signup from './Signup';
import Signin from './Signin';
import ForgotPassword from './forgot-password';
import UserDashboard from './UserDashboard';
import AdminDashboard from './AdminDashboard';
import ShowroomDashboard from './ShowroomDashboard';
import AdminRoute from './AdminRoute';
import NotFound from './NotFound';
const App = () => (<BrowserRouter>
<Header />
<main>
<Routes>
<Route exact path='/' element={<Home />} />
<Route exact path='/signup' element={<Signup />} />
<Route exact path='/signin' element={<Signin />} />
<Route exact path='/forgotpassword' element={<ForgotPassword />} />
<Route exact path='/user/dashboard' element={<UserDashboard />} />
<AdminRoute exact path='/admin/dashboard' element={<AdminDashboard />} />
<Route exact path='/showroom/dashboard' element={<ShowroomDashboard />} />
<Route exact path = '*' element={<NotFound />} />
</Routes>
</main>
</BrowserRouter>
);
export default App;
react-router-dom no longer supports custom route components, preferring now component wrappers that handle the auth logic and render either the children prop or an Outlet for nested routes, or the redirect.
Wrap a single "Route" component:
import React from "react";
import { Navigate } from 'react-router-dom';
import { isAuthenticated } from "../helper/auth";
const AdminRoute = ({ children }) => {
return isAuthenticated()?.role === 1
? children
: <Navigate to='/signin' replace />;
};
...
<Route
path='/admin/dashboard'
element={(
<AuthRoute>
<AdminDashboard />
</AuthRoute>
)}
/>
Wrap nested Route components:
import React from "react";
import { Navigate, Outlet } from 'react-router-dom';
import { isAuthenticated } from "../helper/auth";
const AdminWrapper = () => {
return isAuthenticated()?.role === 1
? <Outlet />
: <Navigate to='/signin' replace />;
};
...
<Route path='/admin/dashboard/*' element={<AdminWrapper />}>
<Route index element={<AdminDashboard />} />
... any other '/admin/dashboard/*' routes ...
</Route>

React Router Dom how to redirect to Other App.js route when you are in any subRoute of any route [duplicate]

This question already has answers here:
React Router works only after refreshing the page
(5 answers)
Closed 1 year ago.
I'm new to react & react router dom v5, also my english is bad. Thank you in advance for helping me.
my problem:
I have 2 Main Routes in my App.js route
import { Suspense } from 'react';
import {BrowserRouter as Router, Switch, Route} from 'react-router-dom'
/* Pges */
import AdminContainer from './Pages/Admin/AdminContainer';
import PublicContainer from './Pages/Public/PublicContainer';
import NotFound from './Pages/NotFound'
import AuthContainer from './Pages/Auth/AuthContainer';
/* Protected Route */
/* Helpers */
function App() {
console.log("APP")
return (
<Suspense fallback={(<p>Loading</p>)}>
<Router>
<Switch>
<Route path="/auth" component={AuthContainer} />
<Route path="/admin" component={AdminContainer} />
<Route path="/*" component={PublicContainer} />
<Route path="*" component={NotFound} />
</Switch>
</Router>
</Suspense>
)
}
export default App;
the authcontainer have 2 sub routes
"/signin"
"/signup"
import React from "react";
import {
BrowserRouter as Router,
Switch,
Route,
withRouter
} from "react-router-dom";
// PAGES
import Signin from "../Auth/Signin";
import Signup from "../Auth/Signup";
const AuthContainer = () => {
console.log("AUTH")
return (
<div>
<Router>
<Switch>
<Route exact path="/auth" component={Signin}/>
<Route exact path="/auth/signin" component={Signin}/>
<Route exact path="/auth/signup" component={Signup}/>
</Switch>
</Router>
</div>
);
};
export default withRouter(AuthContainer);
then the my publiccontainer have 3 sub routes
"/"
"/product"
"/mycart"
/* Dependencies */
import { Route, Switch, BrowserRouter as Router } from 'react-router-dom'
/* Components */
import Header from "../../Components/Header"
import Products from "./Products"
import Home from "./Home"
import UserProfile from "../User/AccountProfile"
import MyCart from '../Public/MyCart'
const PublicContainer = () => {
console.log("PUBLIC")
return (
<div>
<Router>
<Header />
<Switch>
<Route exact path='/' render={(props) => <Home />} />
<Route exact path='/products' render={(props) => <Products />} />
<Route exact path='/mycart' render={(props) => <MyCart isAuth={false} />} />
</Switch>
</Router>
</div>
)
}
export default PublicContainer
the my cart component will only render if isAuth is true, else it will redirect to "/auth/signin"
import React from 'react'
import { Redirect } from 'react-router'
const MyCart = ({isAuth}) => {
if(!isAuth)
return (<Redirect from='*' to='/auth/signin'></Redirect>)
return (
<div>
my cart
</div>
)
}
export default MyCart
The problem is, its trying to redirect to "/auth/signin" but it is still in the "/" page
When i hit reload it finally redirect to "/auth/signin"
How can i fix this issue, I really appreciate your help
UPDATE
this is overview of my planned routes
By the way i think when the mycart isAuth is false then it tries to Link to /auth/signin which causes the link in the top url to correctly point to auth signin, but after that it only checks the subroutes of the publiccontainer instead of checking the app.js routes
But when i reload it, it start searching the correct route from the app.js routes which return the expected route & page which is the sign in
I read a almost similar question in terms of only rendering the correct path when hitting refresh/reload
here React Router works only after refreshing the page
The problem was i'm wrapping the sub routes with a new router, so i tried removing the Router jsx that is wrapping the Switch> & other subroutes in both AuthContainer.js & PublicContainer.js
this is the updated AuthContainer.js
import React from "react";
import {
BrowserRouter as Router,
Switch,
Route,
withRouter
} from "react-router-dom";
// PAGES
import Signin from "../Auth/Signin";
import Signup from "../Auth/Signup";
const AuthContainer = () => {
console.log("AUTH")
return (
<div>
<Switch>
<Route exact path="/auth/signin" component={Signin}/>
<Route exact path="/auth/signup" component={Signup}/>
<Route exact path="/auth" component={Signin}/>
</Switch>
</div>
);
};
export default withRouter(AuthContainer);
And this is the PublicContainer.js
/* Dependencies */
import { Route, Switch } from 'react-router-dom'
/* Components */
import Header from "../../Components/Header"
import Products from "./Products"
import Home from "./Home"
import UserProfile from "../User/AccountProfile"
import MyCart from '../Public/MyCart'
/* Protected */
const PublicContainer = ({toAuth}) => {
console.log("PUBLIC")
return (
<div>
<Header />
<Switch>
<Route exact path='/products' render={(props) => <Products />} />
<Route exact path='/profile' render={(props) => <UserProfile />} />
<Route exact path='/mycart' render={(props) => <MyCart />} />
<Route exact path='/' render={(props) => <Home />} />
</Switch>
</div>
)
}
export default PublicContainer

<Link to = "/cart" ></Link> changes the url but my cart component is not getting rendered

In my app I am using react-router-dom, when I go to the /cart page the url is getting changed but the cart component is not getting rendered.
This is the App.js component :
import React, {useEffect,useState} from 'react';
import {SignUp,SignIn,Homepage,Cart} from './Components'
import {AuthProvider,useAuth} from "./contexts/AuthContext";
import {BrowserRouter as Router, Switch, Route } from 'react-router-dom';
import PrivateRoute from './Components/PrivateRoute/PrivateRoute';
function App(props) {
return (
<Router>
<AuthProvider>
<Switch>
<Route exact path = "/signup" component = {SignUp} />
<Route exact path = "/signin" component = {SignIn} />
{/* <PrivateRoute path = "/cart" component = {Cart} /> */} // Cart component renders but I want to use this in homepage component
<PrivateRoute exact path = "/" component = {Homepage} />
</Switch>
</AuthProvider>
</Router>
);
}
export default App;
This is the HomePage component :
import React, {useState,useEffect} from 'react';
import {Button,Card,Row,Col} from 'react-bootstrap';
import {useAuth} from '../../contexts/AuthContext';
import styles from './HomePage.module.css';
import {firestore} from '../../firebase';
import {BrowserRouter as Router, Switch, Route } from 'react-router-dom';
import {Navbar,Cart} from '../'
function HomePage(props) {
const {currentUser} = useAuth();
const [products,setProducts] = useState([]);
const [itemsInCart,setItemsInCart] = useState(0);
return (
<div>
<Navbar items = {itemsInCart} />
<Route path = "/cart" componenet = {Cart}></Route> // this is not rendering Cartcomponent
<div className = {styles.container}>
{products.map((product,index)=>
<Card style={{ width: '18rem',border:'none' }} key = {index}>
<Card.Img variant="top" src={product.data.img} />
<Card.Body>
<Card.Title>{product.data.title}</Card.Title>
<Row>
<Col><Card.Title>Rs:{product.data.price}</Card.Title></Col>
<Col><Button variant="warning" onClick = {() => handleAddToCard(product)}>Add to Cart</Button></Col>
</Row>
</Card.Body>
</Card>
)}
</div>
</div>
);
}
export default HomePage;
You can use BrowserRouter should be top level tag.
like this app.js
<BrowserRouter>
<Switch>
<Route exact path="/signup" component={SignUp} />
<Route exact path="/signin" component={SignIn} />
{/* <PrivateRoute path = "/cart" component = {Cart} /> */} // Cart
component renders but I want to use this in homepage component
<PrivateRoute exact path="/" component={Homepage} />
</Switch>
</BrowserRouter>;
I don't need to use anything related to the homepage component route.
Just specify it as route component

react-router-dom match object isExact false

I am working on a react project. I try to access the url parameters in the Header component. However, it always returns empty.
import React from 'react';
import { Route, Switch } from 'react-router-dom';
import { ConnectedRouter } from 'connected-react-router'
import SamplePage from './pages/SamplePage';
import PropertyPage from './pages/PropertyPage';
import LoadingPage from './pages/LoadingPage';
import Header from './header/Header';
import ButtonGroup from './ButtonGroup';
import { Container } from 'semantic-ui-react';
import history from '../history';
const App = () => {
return (
<ConnectedRouter history={history}>
<div>
<Switch>
<Route path='/loading' exact component={LoadingPage} />
<Route component={Header} title='Sample page' />
</Switch>
<Container style={{ marginTop: '7em' }}>
<Switch>
<Route
path='/page/:pageType/properties/:propertyId'
exact
component={PropertyPage}
/>
<Route path='/page/:pageType' exact component={SamplePage} />
</Switch>
</Container>
<Switch>
<Route exact path='/loading' render={() => <div />} />
<Route component={ButtonGroup} />
</Switch>
</div>
</ConnectedRouter>
);
}
export default App;
I try to access url params in the Header component. The params is empty, and isExact is false. Can anyone help me with this? Thanks.
From screenshot of console.log, react-router is matching on
<Route component={Header} title='Sample Scorecard' />
This is correct behavior as Switch looks for the first match.
I suggest to not declare rendering for Header as a Route. i.e.
<Switch>
<Route path='/loading' exact component={LoadingPage} />
<Header title='Sample Scorecard' />
</Switch>
This way Switch will only render it when loading path isn't matched.
I still cannot figure out how to solve this issue. What I do to walk around this issue is to create a Higher Order Component. Header will be included in the HOC, then it has no problem to get the URL parameters.

If <notFound/> component get executed add class to <footer/>component . React-Redux

If < notFound /> rout get executed (i.e : if not found page get rendered I want to add class to footer component.
Below is my index.jsx render function
render() {
return (
<div>
<Navbar />
<div className="pageData">
{this.props.children}
// <notFound/> component will get rendered here
</div>
<Footer/>
<LoginPopup />
</div>
)
}
Below is my routes.jsx
import React from 'react'
import { Route, IndexRoute } from 'react-router'
import App from 'layout/app'
import Home from 'pages/home'
import MyWagers from 'containers/myWagersContainer'
import Wagers from 'containers/wagersContainer'
import NotFound from 'pages/notFound'
const ROUTES = (
<Route path='/' component={App}>
<IndexRoute component={Home} />
<Route path="/wagers(/:trackCode)(/:raceNum)" component={Wagers} >
<Route path="*" component={() => (<NotFound status = "404" />)}/>
</Route>
<Route path="/mywagers" component={MyWagers} />
<Route path="*" name = "notFound" component={() => (<NotFound status = "404" />)}/>
</Route> )
export default ROUTES
So can we set something globally or can we get route name so we can add class in footer component as per < notFound / > component get rendered
Use a callback that you pass to this.props.children and then in <NotFound />
componentWillMount() {
this.props.setFooterClass('myclass');
}
componentWillUnmount() {
this.props.setFooterClass('');
}
in index.js:
<NotFound setFooterClass={myClass => this.setState({ footerClass: myClass })} />
and
<Footer className={this.state.footerClass} />
Pass props to children

Resources