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

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

Related

React -router doesn't add component to the dom

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>

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>

Why is rendering the parent component and the child trying to enter the child component

Why is rendering the parent component and the child trying to enter the child component
"react-router-dom": "^6.0.1",
when I enter on the route:
http://localhost:3000/dashboard- the view work
http://localhost:3000/dashboard/employee - rendering dashboard and employee view (both views)
http://localhost:3000/dashboard/accounting - rendering dashboard and accounting view (both views)
Documentation:
https://reactrouter.com/docs/en/v6/getting-started/tutorial#nested-routes
index.js
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter } from "react-router-dom";
import App from "./App";
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById("root")
);
App.js
import AppRouter from "./routers/AppRouter";
function App() {
return (
<>
<AppRouter />
</>
);
}
export default App;
AppRouter.js
import { Route, Routes } from "react-router-dom";
import Navbar from "../components/template/Navbar";
import AccountingHomeView from "../components/views/accounting/AccountingHomeView";
import DashboardHomeView from "../components/views/dashboard/DashboardHomeView";
import EmployeeHomeView from "../components/views/employee/EmployeeHomeView";
import HomeView from "../components/views/public/HomeView";
import LoginView from "../components/views/public/LoginView";
const AppRouter = () => {
return (
<div>
<Navbar />
<Routes>
<Route path="/" element={<HomeView />} />
<Route path="dashboard" element={<DashboardHomeView />}>
<Route path="employee" element={<EmployeeHomeView />} />
<Route path="accounting" element={<AccountingHomeView />} />
</Route>
<Route path="/login" element={<LoginView />} />
</Routes>
</div>
);
};
export default AppRouter;
DashboardHomeView.js (with outlet)
import { Outlet } from "react-router-dom";
const DashboardHomeView = function () {
return (
<>
<h1>DashboardHomeView</h1>
<Outlet />
</>
);
};
export default DashboardHomeView;
component children Accounting
import React from "react";
const AccountingHomeView = function () {
return (
<div>
<h1> Accountin</h1>
</div>
);
};
export default AccountingHomeView;
I also initially found this a bit confusing, but with nested routes the "parent" route is considered more of a "layout" component in that it is always rendered when its path matches, and renders all its children routes into its outlet.
const AppRouter = () => {
return (
<div>
<Navbar />
<Routes>
<Route path="/" element={<HomeView />} />
<Route
path="dashboard"
element={<DashboardHomeView />} // <-- always matched/rendered at "/dashboard*"
>
<Route
path="employee"
element={<EmployeeHomeView />} // <-- conditionally matched/rendered
/>
<Route
path="accounting"
element={<AccountingHomeView />} // <-- conditionally matched/rendered
/>
</Route>
<Route path="/login" element={<LoginView />} />
</Routes>
</div>
);
};
const DashboardHomeView = function () {
return (
<>
<h1>DashboardHomeView</h1> // <-- always matched/rendered at "/dashboard*"
<Outlet /> // <-- conditionally matched/rendered children
</>
);
};
Nested-Routes
You may have noticed when clicking the links that the layout in App
disappears. Repeating shared layouts is a pain in the neck. We've
learned that most UI is a series of nested layouts that almost always
map to segments of the URL so this idea is baked right in to React
Router.
I believe what you are expecting is what is called an Index Route. It is what would be rendered on a "/dashboard" route when it isn't a layout/wrapper container.
Notice it has the index prop instead of a path. That's because the
index route shares the path of the parent. That's the whole point--it
doesn't have a path.
Maybe you're still scratching your head. There are a few ways we try
to answer the question "what is an index route?". Hopefully one of
these sticks for you:
Index routes render in the parent routes outlet at the parent route's path.
Index routes match when a parent route matches but none of the other children match.
Index routes are the default child route for a parent route.
Index routes render when the user hasn't clicked one of the items in a navigation list yet.
const AppRouter = () => {
return (
<div>
<Navbar />
<Routes>
<Route path="/" element={<HomeView />} />
<Route path="dashboard" element={<DashboardLayout />}>
<Route path="employee" element={<EmployeeHomeView />} />
<Route path="accounting" element={<AccountingHomeView />} />
<Route index element={<DashboardHomeView />} />
</Route>
<Route path="/login" element={<LoginView />} />
</Routes>
</div>
);
};
const DashboardLayout = function () {
return (
<div /* with any layout styling */>
.... other common layout content
<Outlet />
.... more possible common page content
</div>
);
};
const DashboardHomeView = function () {
return (
<>
<h1>DashboardHomeView</h1>
.... dashboard specific content
</>
);
};
How about using the exact prop for the parent Route. Like <Route exact path="dashboard" element={<DashboardHomeView />}>. This may solve the issue.

why Route is not working with my react app?

I am trying to develop react application. The problem is when I use the Route and Switch, it is not working. Actually, nothing is happening. Could anyone please give me a clue about the possible problem here?
Here is my code:
import React, { Component } from 'react';
import Home from './HomeComponent';
import Menu from './MenuComponent';
import { DISHES } from '../shared/dishes';
import DishDetailComponent from './DishdetailComponent';
import Header from './HeaderComponent';
import Footer from './FooterComponent';
import { Switch, Route, Redirect, BrowserRouter as Router } from 'react-router-dom';
class Main extends Component {
constructor(props) {
super(props);
this.state = {
dishes: DISHES
};
}
render() {
const HomePage = () => {
return(
<Home />
);
}
return (
<div>
<Header />
<Router>
<Switch>
<Route path="/home" Component={HomePage} />
<Route path="/menu" Component={() => <Menu dishes={this.state.dishes} />} />
<Redirect to="home" />
</ Switch>
</Router>
<Footer />
</div>
);
}
}
The obvious mistake is that you have capitalized the "C" in the component prop, so you should call it like component={HomePage}
Here are some other things you could improve upon though:
If you are gonna use an inline function, it is preferable to use the render prop, and if you are gonna use a component directly, preferable to just use Component prop. Moreover:
const HomePage = () => {
return(
<Home />
);
}
is unnecessary as you can just use the Home component directly.
Try this for your render() function:
render() {
return (
<div>
<Header />
<Router>
<Switch>
<Route path="/home" component={Home} />
<Route path="/menu" render={() => <Menu dishes={this.state.dishes} />} />
<Redirect to="home" />
</ Switch>
</Router>
<Footer />
</div>
);
}

react-router-native <Redirect> renders blank page

The logic seems simple, though I've tried a half-dozen permutations to see if anything changes. I have no idea why react-router is behaving this way:
import React from 'react'
import { View, Text } from 'react-native'
import { observer, inject } from 'mobx-react'
import { NativeRouter, Link, Route, Redirect, Switch } from 'react-router-native'
import Welcome from './welcome'
import Tutorial from './tutorial'
import Plants from './plants'
#inject('store')
#observer
class Main extends React.Component {
render() {
const newUser = true //this.props.store.plants.length === 0
const home = newUser ? '/welcome' : '/plants'
return (
<Switch>
<Route path='/plants' component={Plants} />
<Route path='/tutorial' component={Tutorial} />
<Route path='/welcome' component={Welcome} />
<Redirect to={home} />
<Route path='/' component={Welcome} />
</Switch>
)
}
}
export default Main
The final 'welcome' should be unnecessary, but I've put it there to test: if I remove the then welcome does appear, so it's clearly the that's causing a blank page to render.
This is the render() method of the top-level component:
return (
<Provider store={store}>
<NativeRouter>
<Main />
</NativeRouter>
</Provider>
)
This is based on the example at https://reacttraining.com/react-router/native/guides/philosophy which shows a Switch, Route, and Redirect all being used without an enclosing Router:
const App = () => (
<AppLayout>
<Route path="/invoices" component={Invoices}/>
</AppLayout>
)
const Invoices = () => (
<Layout>
{/* always show the nav */}
<InvoicesNav/>
<Media query={PRETTY_SMALL}>
{screenIsSmall => screenIsSmall
// small screen has no redirect
? <Switch>
<Route exact path="/invoices/dashboard" component={Dashboard}/>
<Route path="/invoices/:id" component={Invoice}/>
</Switch>
// large screen does!
: <Switch>
<Route exact path="/invoices/dashboard" component={Dashboard}/>
<Route path="/invoices/:id" component={Invoice}/>
<Redirect from="/invoices" to="/invoices/dashboard"/>
</Switch>
}
</Media>
</Layout>
)
Use the NativeRouter as the topmost component in your Main component and it will work as expected.
#inject('store')
#observer
class Main extends React.Component {
render() {
const newUser = true //this.props.store.plants.length === 0
const home = newUser ? '/welcome' : '/plants'
return (
<NativeRouter>
<Switch>
<Route path='/plants' component={Plants} />
<Route path='/tutorial' component={Tutorial} />
<Route path='/welcome' component={Welcome} />
<Redirect to={home} />
</Switch>
</NativeRouter>
)
}
}

Resources