Problems to match classes based on route in React - javascript

I've got a problem with assigning a class to the variable and then to the div based on his routing. I don't know what am I doing wrong, everything seems to be ok so where is the mistake then? I'm super curious about what did I do wrong.
import React from 'react'
import {
BrowserRouter as Router,
Switch,
Route,
Link
} from "react-router-dom";
import { useLocation } from "react-router-dom";
import { useEffect } from 'react';
import { makeStyles } from '#material-ui/core/styles';
import About from './About'
import Home from './Home'
const useStyles = makeStyles({
home: {
background: 'white',
},
about: {
background: 'black',
}
});
const App = () => {
const classes = useStyles();
let location = useLocation();
let style;
useEffect(() => {
style = classes.home
handleLocation()
console.log('.')
}, [location])
const handleLocation = () => {
if (location.pathname === "/") {
style = classes.home
} else if (location.pathname === '/about') {
style = classes.about
}
}
return (
<div className={style}>
<Router>
<Switch>
<Route path="/" exact>
<Home />
</Route>
<Route path="/about">
<About />
</Route>
</Switch>
</Router>
</div>
)
}
export default App
If something is unclear feel free to ask :)

try this code :
import React from 'react'
import {
BrowserRouter as Router,
Switch,
Route,
Link
} from "react-router-dom";
import { useLocation } from "react-router-dom";
import { useEffect } from 'react';
import { makeStyles } from '#material-ui/core/styles';
import About from './About'
import Home from './Home'
const useStyles = makeStyles({
home: {
background: 'white',
},
about: {
background: 'black',
}
});
const App = () => {
const classes = useStyles();
let location = useLocation();
const handleLocation = () => {
if (location.pathname === "/") {
return classes.home
} else if (location.pathname === '/about') {
return classes.about
}else if(more if you want){
return more class ....
}
}
return (
<div className={handleLocation()}>
<Router>
<Switch>
<Route path="/" exact>
<Home />
</Route>
<Route path="/about">
<About />
</Route>
</Switch>
</Router>
</div>
)
}
export default App

React's components re-renders when a state or a prop change, so the style variable is neither a state nor a prop, Now when you update it, UI doesn't change because the component doesn't re-render
import React from 'react'
import {
BrowserRouter as Router,
Switch,
Route,
Link
} from "react-router-dom";
import { useLocation } from "react-router-dom";
import { useEffect } from 'react';
import { makeStyles } from '#material-ui/core/styles';
import About from './About'
import Home from './Home'
const useStyles = makeStyles({
home: {
background: 'white',
},
about: {
background: 'black',
}
});
const App = () => {
const classes = useStyles();
let location = useLocation();
return (
<div className={ location.pathname === "/" ? classes.home : location.pathname === "/about" ? classes.about : "" }>
<Router>
<Switch>
<Route path="/" exact>
<Home />
</Route>
<Route path="/about">
<About />
</Route>
</Switch>
</Router>
</div>
)
}
export default App
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
.
You would need to either make style a state or secondly you can just do this directly

Related

How to prevent components from unmounting when path changes?

Is there a way to stop the route from unmounting? In my app I would need to keep react state between switching the routes.
Here you can see that, if we change route then home respective route component will mount and unmount. I don't want.
CODESANDBOX DEMO
I've looked in
How can I prevent the unmount in React Components?
How can I prevent React from unmounting/remounting a component?
but doesn't work for me.
index.js
import React from "react";
import { createRoot } from "react-dom/client";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import App from "./App";
import First from "./routes/First";
import Second from "./routes/Second";
const rootElement = document.getElementById("root");
const root = createRoot(rootElement);
root.render(
<BrowserRouter>
<Routes>
<Route path="" element={<App />} />
<Route path="first" element={<First />} />
<Route path="second" element={<Second />} />
</Routes>
</BrowserRouter>
);
App.js
import * as React from "react";
import { Link } from "react-router-dom";
export default function App() {
return (
<div>
<h1>Prevent Routing</h1>
<nav
style={{
borderBottom: "solid 1px",
paddingBottom: "1rem"
}}
>
<Link to="/first">First</Link> |<Link to="/second">Second</Link>
</nav>
</div>
);
}
First.js
import * as React from "react";
import { useEffect } from "react";
import { Link } from "react-router-dom";
export default function First() {
useEffect(() => {
console.log("mounted First");
return () => console.log("unmounted First");
}, []);
return (
<main style={{ padding: "1rem 0" }}>
<Link to="/">Home</Link>
<h2>First</h2>
</main>
);
}
Second.js
import * as React from "react";
import { useEffect } from "react";
import { Link } from "react-router-dom";
export default function Second() {
useEffect(() => {
console.log("mounted Second");
return () => console.log("unmounted Second");
}, []);
return (
<main style={{ padding: "1rem 0" }}>
<Link to="/">Home</Link>
<h2>Second</h2>
</main>
);
}
React Router will always unmount the component when it's not matched by a path.
You could fix this by combining both Components with a double route, each component can determine what he will render based on the current path.
So the main routing will look something like:
<Route path={[ '/first', '/second' ]}>
<First {...{}} />
<Second {...{}} />
</Route>
Then use useLocation in the component to toggle the render:
import { useLocation } from "react-router-dom";
function First(props) {
const location = useLocation();
if (location.pathname !== '/first') {
return null
}
}

No routes matched location "/rewards-store"

I have a problem with the router V6. The routes are not being rendered. The homepage use to have all the products and now I cannot see any of the products shown, also I have my code to the links that go to every part of the website but is not appearing. The error that appears is:
react_devtools_backend.js:4045 No routes matched location "/rewards-store-andrea-lopez-bravo"
at Routes (http://localhost:3000/rewards-store-andrea-lopez-bravo/static/js/vendors~main.chunk.js:32538:5)
at Router
at div
at App (http://localhost:3000/rewards-store-andrea-lopez-bravo/static/js/main.chunk.js:423:63)
at Router (http://localhost:3000/rewards-store-andrea-lopez-bravo/static/js/vendors~main.chunk.js:32471:15)
at BrowserRouter (http://localhost:3000/rewards-store-andrea-lopez-bravo/static/js/vendors~main.chunk.js:31958:5)
at AppProvider (http://localhost:3000/rewards-store-andrea-lopez-bravo/static/js/main.chunk.js:4188:5)
index.tsx:25 No routes matched location "/rewards-store"
This my router:
import { Routes, Route } from "react-router-dom";
import { Home } from "../pages/Home";
import { History } from "../pages/History";
import { Points } from "../pages/Points";
import { NotFound } from "../components/notification/NotFound";
export const Router = () => {
return (
<Routes>
<Route path="/" element={<Home />} />
<Route path="/history" element={<History/>}/>
<Route path="points" element={<Points/>}/>
<Route path="NotFound" element={<NotFound/>} />
</Routes>
);
};
This is index:
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import AppProvider from "./context/AppContext";
import { BrowserRouter } from "react-router-dom";
ReactDOM.render(
<React.StrictMode>
<AppProvider>
<BrowserRouter>
<App />
</BrowserRouter>
</AppProvider>
</React.StrictMode>,
document.getElementById("root")
);
AppContext:
import React,{ useState } from "react";
import { usePagination } from "../components/utils/pagination.jsx";
export const AppContext = React.createContext();
export default function AppProvider({ children }) {
const [user,setUser] = useState({})
const [points, setPoints] = useState(0)
const [products, setProducts] = useState([])
const [reedemStatus, setReedemStatus] = useState({})
const [history, setHistory] = useState([])
const paginationList = usePagination(products, 16)
const paginationHistoryList = usePagination(history, 16)
const totalProducts = products.length
const totalHistory = history.length
const handlerAddPoint =(value)=>{
const newUser = {...user}
newUser.points = user.points + value
setUser(newUser)
}
const handlerSubtractPoint =(points)=>{
const newUser = {...user}
newUser.points = user.points - points
setUser(newUser)
}
return(
<AppContext.Provider value={{user,
setUser,
handlerAddPoint,
handlerSubtractPoint,
points,
setPoints,
products,
setProducts,
totalProducts,
paginationList,
reedemStatus,
setReedemStatus,
history,
setHistory,
paginationHistoryList,
totalHistory}}>
{children}
</AppContext.Provider>
);
}
App.js
import React, { useEffect, useContext } from "react";
import "./App.css";
import { Header } from "./components/header/Header";
import { Nav } from "./components/nav/Nav.jsx";
import { getUser } from "./services/users";
import { AppContext } from "./context/AppContext";
import { Notification } from "./components/notification/Notification";
import { Router } from "./routers/Router";
function App() {
const { setUser } = useContext(AppContext);
useEffect(() => {
getUser().then((user) => {
setUser(user);
});
}, [setUser]);
return (
<div className="App">
<Notification />
<Nav />
<Header />
<Router />
</div>
);
}
export default App;
In the menu.jsx the links are not rendering:
import "./Menu.css";
import React from "react";
import { Link } from "react-router-dom";
export const Menu =()=>{
return(
<ul className="menu flex-row">
<li className="pink-line"><Link className="normal-text" to="/acamica-rewards-store/">Home</Link></li>
<li className="pink-line"><Link className="normal-text" to="/acamica-rewards-store/points">Add points</Link></li>
<li className="pink-line"><Link className="normal-text" to="/acamica-rewards-store/history">History</Link></li>
</ul>
)
}
In your router always put the home route at the very bottom!
<Routes>
<Route path="/history" element={<History/>}/>
<Route path="points" element={<Points/>}/>
<Route path="NotFound" element={<NotFound/>} />
<Route path="/" element={<Home />} />
</Routes>
or make sure to make the home path as exact!
<Routes>
<Route exact path="/" element={<Home />} />
<Route path="/history" element={<History/>}/>
<Route path="points" element={<Points/>}/>
<Route path="NotFound" element={<NotFound/>} />
</Routes>
I did this in v.6
<Route path="/cart" element={<CartPage />}>
<Route path=":id" element={<CartPage />} />
</Route>

React-router-dom Protected Routes are not working

Protected Routes.js:
In protected routes you can see I'm using directly false in if statement but I'm still able to see that page why?
import React from 'react';
import { Route } from 'react-router-dom';
// import Auth from './User/Auth';
import Error401 from './Error/401';
// create a component for protected route
console.log('Routes.js');
export const ProtectedRoute = ({ element: Element, ...rest }) => {
console.log("Function Called")
return (
<Route {...rest} render={props => {
if(false){
return <Element {...props} />
}else{
return <Error401 />
}
}
} />
)
}
App.js:
This is app.js where I'm using protected routes component
import './App.css';
import React from 'react';
import { BrowserRouter, Route, Routes } from 'react-router-dom';
import { Layout } from 'antd';
import { MoneyCollectOutlined } from '#ant-design/icons';
import Login from './Components/User/Login';
import Signup from './Components/User/Signup';
import {ProtectedRoute} from './Components/Routes';
import Error404 from './Components/Error/404';
function App() {
return (
<BrowserRouter>
<Layout style={{minHeight:"100vh"}}>
<Layout.Header>
<h1 style={{color:"white"}} align="center"> <MoneyCollectOutlined/>MoneyG</h1>
</Layout.Header>
<Layout.Content style={{minHeight:"100%"}}>
<Routes>
<ProtectedRoute exact path="/register" element={<Signup/>} />
<ProtectedRoute exact path="/login" element={<Login/>} />
<Route path="*" element={<Error404/>} />
</Routes>
</Layout.Content>
</Layout>
</BrowserRouter>
);
}
export default App;
First, <Routes> elements should only have <Route> elements as children. You should move your protection logic down a layer.
Secondly, the render prop doesn't exist anymore in V6. It was replaced in favor of element. See doc.
Here is how you might tackle it:
<Routes>
<Route exact path="/register" element={(
<ProtectedRoute>
<Signup/>
</ProtectedRoute>
)} />
<Route exact path="/login" element={(
<ProtectedRoute>
<Login/>
</ProtectedRoute>
)} />
<Route path="*" element={<Error404/>} />
</Routes>
And:
const ProtectedRoute = () => {
if (condition) { return <Error401 />; } // You might as well use Navigate here
return children;
};
you can use createContext & useContext
//store/AuthApi.jsx
import { createContext } from "react";
const AuthApi = createContext();
export default AuthApi;
Then define the context app.jsx
import React, from 'react'
import { AllRoutes } from 'routes/Routes';
import { BrowserRouter as Router } from "react-router-dom";
import AuthApi from 'store/AuthApi';
const App = () => {
const [user, setUser] = useState(false);
useEffect(() => {
// you can get user from localStorage or Cookie(js-cookie npm)
//then you can change user state true or false
}, [])
return (
<>
<AuthApi.Provider value={{ user, setUser }}>
<Router>
<AllRoutes />
</Router>
</AuthApi.Provider>
<Toast />
</>
)
}
export default App
then see AllRoutes
//routes/Routes
import React, { useContext } from "react";
import { Routes, Route } from "react-router-dom";
import { SignIn, SignUp, Dashboard } from "pages";
import AuthApi from "store/AuthApi";
export const ProtectedRouting = () => {
return (
<Routes >
<Route path='/' exact element={<Dashboard />} />
// add more protected routes
</Routes>
)
}
export const AuthRouting = () => {
return (
<Routes >
<Route exact={true} path='/sign-in' element={<SignIn />} />
<Route exact={true} path='/sign-up' element={<SignUp />} />
</Routes>
)
}
export const AllRoutes = ()=> {
const context = useContext(AuthApi);
console.log(context.user)
return (
context.user ?
<ProtectedRouting />
: <AuthRouting />
)
}
pages/SignIn.jsx
import React,{ useContext } from 'react';
import AuthApi from "store/AuthApi";
const SignIn = () => {
const context = useContext(AuthApi);
const signInSubmit =(e)=> {
e.preventDefault();
//post request to signin
// if login is successfull then save user or token in cookie or localStorage or something
context?.setUser(true);
//...
}
return (
//signin code here
<form onSubmit={signInSubmit}>
///input here
</form>
)
}
export default SignIn

React not rendering correctly layout after redirect

I have an app that uses styled-components and material-ui. I have private routes configurated, based on the user role and if the user is not authenticated I should return him to login page. But when that happen the layout do no load.
App.tsx
import React from 'react';
import { MuiThemeProvider, createMuiTheme } from '#material-ui/core';
import { Provider } from 'react-redux';
import { ToastContainer } from 'react-toastify';
import { PersistGate } from 'redux-persist/integration/react';
import { ThemeProvider as StyledThemeProvider } from 'styled-components';
import Routes from './routes';
import { configureStore } from './store/configure-store';
import GlobalStyle from './styles/globalTheme';
import defaultTheme from './styles/theme/default.theme';
const { store, persistor } = configureStore();
const theme = createMuiTheme({});
function App() {
return (
<Provider store={store}>
<MuiThemeProvider theme={theme}>
<StyledThemeProvider theme={defaultTheme}>
<PersistGate loading={null} persistor={persistor}>
<GlobalStyle />
<Routes />
<ToastContainer />
</PersistGate>
</StyledThemeProvider>
</MuiThemeProvider>
</Provider>
);
}
export default App;
routes.tsx
import React, { memo } from 'react';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import NotFound from '../components/NotFound';
import Dashboard from '../pages/Dashboard';
import Login from '../pages/Login';
import Register from '../pages/Register';
import { ProtectedRoute } from './permissions-route';
function Routes() {
return (
<BrowserRouter>
<Switch>
<ProtectedRoute
path="/dashboard"
component={Dashboard}
requiredRole={['USER']}
/>
<Route exact path="/" component={Login} />
<Route exact path="/login" component={Login} />
<Route exact path="/cadastro" component={Register} />
<Route exact path="/error" component={NotFound} />
</Switch>
</BrowserRouter>
);
}
export default memo(Routes);
permission-route.tsx
import React from 'react';
import { useSelector } from 'react-redux';
import { Route, Redirect } from 'react-router-dom';
import { RootState } from '../store/configure-store';
interface Teste {
path: any;
component: any;
render?: any;
requiredRole: any;
}
export const ProtectedRoute = ({
path,
component: Component,
render,
requiredRole,
...rest
}: Teste) => {
const userRole = useSelector((state: RootState) => state.user.role);
return (
<Route
path={path}
{...rest}
render={(props) => {
if (requiredRole.includes(userRole)) {
return Component ? <Component {...props} /> : render(props);
}
return <Redirect to="/login" />;
}}
/>
);
};
export default ProtectedRoute;
What happens after redirect occurs
Instead of returning the <Redirect /> component, try window.location.href = "/login";
return (
<Route
path={path}
{...rest}
render={(props) => {
if (requiredRole.includes(userRole)) {
return Component ? <Component {...props} /> : render(props);
}
window.location.href = "/login";
}}
/>
);
This should refresh the page and make it get the proper stylings again
I had a similar issue using MUI and Router.
I found that I was importing different versions of MUI: #mui and #material-ui after replacing #material-ui components and uninstalling it, the issue was resolved.
Most likely this is an issue with conflicting styling.
I suggest checking browser DevTools to see what files/classes are overriding these styles after redirect.

React Redux routing issues

I have recently experienced some issues with my react router and redux. Basically, I have a redux value set which let's me know if an item is selected. If the item is selected, then it will allow a URL to be used. One thing that I have noticed. If I add a redirect function. It breaks everything
Authentication function:
import React, { Component, Fragment } from "react";
import { Provider } from "react-redux";
// import store from "./store";
import {
BrowserRouter as Router,
Switch,
Route,
Redirect
} from "react-router-dom";
import { connect } from "react-redux";
import Profile from "./Profile";
import AddDomain from "./AddDomain";
import ChoosePackage from "./ChoosePackage";
import DashboardHome from "./DashboardHome";
import { Elements } from "#stripe/react-stripe-js";
import PropTypes from "prop-types";
import { loadStripe } from "#stripe/stripe-js";
const stripePromise = loadStripe("pk_test_7S0QSNizCdsJdm9yYEoRKSul00z4Pl6qK6");
class index extends Component {
componentDidMount() {
console.log("DOMAIN NAME" + this.props.domain_name);
}
state = {
domain_name: ""
};
static propTypes = {
domain_name: PropTypes.string.isRequired
};
domainCheck = () => {
if (this.props.domain_name != "") {
return <ChoosePackage />;
} else {
console.log("running rediect");
return <Redirect to="/dashboard" />;
}
};
render() {
return (
<React.Fragment>
<Route path="/dashboard/add-domain/choose-package">
{this.domainCheck()}
</Route>
<Route exact path="/dashboard/add-domain">
<AddDomain />
</Route>
<Route exact path="/dashboard/profile">
<Profile />
</Route>
<Route exact path="/dashboard">
<DashboardHome />
</Route>
</React.Fragment>
);
}
}
const mapStateToProps = state => ({
domain_name: state.domain.domain_name
});
index.defaultProps = {
domain_name: ""
};
export default connect(mapStateToProps, { pure: false })(index);
Any help is greatly appreciated

Categories