I have main react application which I want to split to 2 applications - using only one host. The split should be performed using routes.
This is my my main app routing:
import React, { Suspense } from 'react';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import DesktopApp from './components/DesktopApp';
import MobileApp from './components/MobileApp';
import classes from './App.module.scss';
interface Props { }
const AppView: React.FC<Props> = (props: React.PropsWithChildren<Props>) => {
return (
<BrowserRouter>
<Suspense fallback={null}>
<Switch>
<Route path="/mobile" component={MobileApp} />
<Route path="**" component={DesktopApp} />
</Switch>
</Suspense>
</BrowserRouter>
);
};
AppView.displayName = 'AppView';
AppView.defaultProps = {};
export default React.memo(AppView);
This is my MobileApp component:
import React, { Suspense } from 'react';
import { Route, Switch, Redirect } from 'react-router-dom';
import classes from './MobileApp.module.scss';
const ScanPayment = React.lazy(() => import('./pages/mobile/ScanPayment/ScanPayment'));
interface Props { }
const MobileAppView: React.FC<Props> = (props: React.PropsWithChildren<Props>) => {
return (
<Suspense fallback={null}>
<Switch>
<Route path="/mobile/scan-payment"></Route>
<Redirect path="**" to="/mobile/scan-payment" />
</Switch>
</Suspense>
);
};
MobileAppView.displayName = 'MobileAppView';
MobileAppView.defaultProps = {};
export default React.memo(MobileAppView);
DesktopApp component (please focus the routes - the rest are really irrelevant):
import React, { Suspense } from 'react';
import { Route, Switch, Redirect } from 'react-router-dom';
import AuthIntro from './pages/desktop/AuthIntro/AuthIntro';
import SideNav from './pages/desktop/SideNav/SideNav';
import Nav from './pages/desktop/Nav/Nav';
import { IUser } from '../models/user';
import classes from './DesktopApp.module.scss';
const Login = React.lazy(() => import('./pages/desktop/Login/Login'));
const Register = React.lazy(() => import('./pages/desktop/Register/Register'));
const ForgotPassword = React.lazy(() => import('./pages/desktop/ForgotPassword/ForgotPassword'));
const Dashboard = React.lazy(() => import('./pages/desktop/Dashboard/Dashboard'));
const UpdateDetails = React.lazy(() => import('./pages/desktop/UpdateDetails/UpdateDetails'));
const RepresentativesList = React.lazy(() => import('./pages/desktop/RepresentativesList/RepresentativesList'));
const AddRepresentative = React.lazy(() => import('./pages/desktop/AddRepresentative/AddRepresentative'));
const UpdateRepresentative = React.lazy(() => import('./pages/desktop/UpdateRepresentative/UpdateRepresentative'));
const NewPayment = React.lazy(() => import('./pages/desktop/NewPayment/NewPayment'));
interface Props {
loggedIn: boolean | null;
user: IUser | null;
}
const DesktopAppView: React.FC<Props> = (props: React.PropsWithChildren<Props>) => {
return (
<Suspense fallback={null}>
{props.loggedIn === false && (
<React.Fragment>
<AuthIntro />
<Switch>
<Route path="/login" component={Login} />
<Route path="/register" component={Register} />
<Route path="/forgot-password" component={ForgotPassword} />
<Redirect path="**" to="/login" />
</Switch>
</React.Fragment>
)}
{props.loggedIn && (
<React.Fragment>
<SideNav />
<div className={classes['container']}>
<Nav
officeName={props.user!.officeName}
BNNumber={props.user!.BNNumber}
/>
<Switch>
<Route path="/dashboard" component={Dashboard} />
<Route path="/update-details" component={UpdateDetails} />
<Route path="/representatives-list" component={RepresentativesList} />
<Route path="/add-representative" component={AddRepresentative} />
<Route path="/update-representative/:id" component={UpdateRepresentative} />
<Route path="/new-payment" component={NewPayment} />
<Redirect path="**" to="/dashboard" />
</Switch>
</div>
</React.Fragment>
)}
</Suspense>
);
};
DesktopAppView.displayName = 'DesktopAppView';
DesktopAppView.defaultProps = {};
export default React.memo(DesktopAppView);
Accessing the desktop routes is working great, but I can't access the mobile routes.
When I go to the url http://localhost:4200/mobile/scan-payment I see blank page. no HTML at all (but of course there should be HTML code)..
Any help?
You missing property component for the <Route /> in MobileView:
import React, { Suspense } from 'react';
import { Route, Switch, Redirect } from 'react-router-dom';
import classes from './MobileApp.module.scss';
const ScanPayment = React.lazy(() => import('./pages/mobile/ScanPayment/ScanPayment'));
interface Props { }
const MobileAppView: React.FC<Props> = (props: React.PropsWithChildren<Props>) => {
return (
<Suspense fallback={null}>
<Switch>
<Route path="/mobile/scan-payment" component={ScanPayments}></Route>
<Redirect path="**" to="/mobile/scan-payment" />
</Switch>
</Suspense>
);
};
MobileAppView.displayName = 'MobileAppView';
MobileAppView.defaultProps = {};
export default React.memo(MobileAppView);
Related
The problem is that when I start using React.lazy, input styles are not rendering correctly. With lazy I get default Antd input styles, not mine. What's the problem and how I can fix it? You can see my code and its results in the pictures below. Thanks!
This picture shows styles that this component should render
This picture shows what styles are applied when using lazy
Code with lazy
import { lazy, Suspense } from 'react';
import { Routes, Route, Navigate } from 'react-router-dom';
import { useAppSelector } from '../../../hooks/redux-hooks';
import { selectCurrentUser } from '../../../store/slices/user/userSelectors';
import { Spinner } from '../../common/Spinner/Spinner';
const HomePage = lazy(() => import('../../../pages/HomePage'));
const ShopPage = lazy(() => import('../../../pages/ShopPage'));
const CheckoutPage = lazy(() => import('../../../pages/CheckoutPage'));
const AuthPage = lazy(() => import('../../../pages/AuthPage'));
export const AppRoutes = () => {
const currentUser = useAppSelector(selectCurrentUser);
return (
<Suspense fallback={<Spinner />}>
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="shop/*" element={<ShopPage />} />
<Route path="checkout" element={<CheckoutPage />} />
<Route
path="auth"
element={currentUser ? <Navigate to="/" /> : <AuthPage />}
/>
</Routes>
</Suspense>
);
};
Code without lazy
import { Routes, Route, Navigate } from 'react-router-dom';
import { useAppSelector } from '../../../hooks/redux-hooks';
import { selectCurrentUser } from '../../../store/slices/user/userSelectors';
import HomePage from '../../../pages/HomePage';
import ShopPage from '../../../pages/ShopPage';
import AuthPage from '../../../pages/AuthPage';
import CheckoutPage from '../../../pages/CheckoutPage';
export const AppRoutes = () => {
const currentUser = useAppSelector(selectCurrentUser);
return (
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="shop/*" element={<ShopPage />} />
<Route path="checkout" element={<CheckoutPage />} />
<Route
path="auth"
element={currentUser ? <Navigate to="/" /> : <AuthPage />}
/>
</Routes>
);
};
I'm trying to get an id from the useParams, but getting Property employeeId does not exist on type error and I don't understand why.
Here is the routes.tsx
//I omitted all the imports here
import React from 'react';
import { BrowserRouter as Router, Routes, Route, Outlet } from 'react-router-dom';
const DefaultContainer = (): JSX.Element => (
<div>
<div id="header">
<Header />
</div>
<div>
<div id="main-container">
<Outlet />
</div>
</div>
</div>
);
const AllRoutes = () => (
<Router>
<Routes>
<Route path="/login" element={<Login />} />
<Route path="/" element={<DefaultContainer />}>
<PrivateRoute path="/" element={<Home />} />
<PrivateRoute path="/e/employees" element={<EmployeeList />} />
<PrivateRoute path="/e/add" element={<AddEmployee />} />
<PrivateRoute path="/e/:employeeId" element={<Employee />} />
<PrivateRoute path="/e/update/:employeeId" element={<UpdateEmployee />} />
</Route>
</Routes>
</Router>
);
export default AllRoutes;
Here is my UpdateEmployee.component.tsx
import React from 'react';
import { useParams } from 'react-router';
const UpdateEmployee = () => {
const { employeeId } = useParams();
console.log(employeeId);
return <h1>hello world</h1>
}
In the routes.tsx there is /e/:employeeId it is working fine.
I also tried adding type for employeeId as string, but still no luck.
Really appreciate your help.
PrivateRoutes.component.tsx
import React from 'react';
import { Navigate, Route } from 'react-router-dom';
import { useAppDispatch, useAppSelector } from '../../hooks/reduxHooks';
import { setUser } from '../../services/reducers/Auth.reducer';
const PrivateRoute = ({ element, ...rest }) => {
const dispatch = useAppDispatch();
const localStorageData = localStorage.getItem('user');
const user = localStorageData ? JSON.parse(localStorageData) : null;
if (!user) {
return <Navigate to="/login" />;
}
// This will reload the user from localstorage in redux state.
const stateUser = useAppSelector((state) => state.auth.user);
if (!stateUser) {
dispatch(setUser(user));
}
return <Route element={element} {...rest} />;
};
export default PrivateRoute;
Try with setting to any type, this worked for me.
const { employeeId } : any = useParams();
I am creating a login in using react on the client and node on the server. From node I make the routes visible to the client, they are used with react router dom. This is my configuration of react router dom:
// React
import { Component, Fragment, Suspense, lazy } from "react";
// Components
import { Loading } from "./Loading";
// Librarys
import {
BrowserRouter as Router,
Switch,
Route,
Redirect,
} from "react-router-dom";
// Layout
const Header = lazy(() => import("./Header"));
const Footer = lazy(() => import("./Footer"));
const PageNotFound = lazy(() => import("./PageNotFound"));
// Pages
const Home = lazy(() => import("./Home"));
const Products = lazy(() =>
import("./Products")
);
const Product = lazy(() =>
import("./Product")
);
// User Pages
const Login = lazy(() => import("./Login"));
const Register = lazy(() => import("./Register"));
class App extends Component {
render() {
return (
<Suspense
fallback={
<Loading />
}
>
<Router>
<Switch>
<Page path="/" component={Home} />
<Page path="/products" component={Products} />
<Page path="/products/:product" component={Product} />
<Page path="/contact" component={Contact} />
<Page path="/admin?login=true" component={Login} />
<Page path="/admin?register=true" component={Register} />
<Route
exact
path="/page-not-found"
component={PageNotFound}
/>
<Redirect to="/page-not-found" />
</Switch>
</Router>
</Suspense>
);
}
}
export default App;
class Page extends Component {
static defaultProps = {
exact: true,
sensitive: true
};
render() {
return (
<Fragment>
<Header />
<Route {...this.props} exact sensitive />
<Footer />
</Fragment>
);
}
}
My problem is in the "Login" and "Register" paths. They have added: "?login=true" and "?register=true". When entering any of those paths it shows me the 404 page. How to solve this? Use routes with parameters.
I'm attempting to create a private route based on the answers here, however it is not performing the redirect.
This is my private route component
import React, { Component, useContext } from "react";
import { Redirect, Route, RouteComponentProps, RouteProps } from "react-router-dom";
import { RootStoreContext } from "../stores/rootStore";
import { observer } from "mobx-react-lite";
const PrivateRoute: React.FC<RouteProps> = ({ children, ...rest }) => {
const rootStore = useContext(RootStoreContext);
const { isAuthenticated } = rootStore.msalStore;
return (
<Route
{...rest}
render={(props: RouteComponentProps<{}>) =>
isAuthenticated ? (
<Component {...props} />
) : (
<Redirect to={{ pathname: "/", state: { from: props.location } }} />
)
}
/>
);
};
export default observer(PrivateRoute);
And this is my App.tsx
//Imports
const App: React.FC = () => {
return (
<>
<BrowserRouter>
<ThemeProvider theme={theme}>
<Route exact path="/" component={LoginPage} />
<Route path="/authcallback" component={AuthCallback} />
<PrivateRoute path="/home" component={HomePage} />
</ThemeProvider>
</BrowserRouter>
</>
);
};
export default App;
When I type /home in the browser, or create a test button that navigates to home, it loads the component even though isAuthenticated = false.
I know it's not related to the value of isAuthenticated in my mobx store as changing to const [isAuthenticated, setIsAuthenticated] = useState(false); doesn't work either. I also have no other instances of routing in my app.
What could be the issue here?
use Switch (from react-router-dom) to wrap routes,
import { Switch } from "react-router-dom";
const App: React.FC = () => {
return (
<>
<BrowserRouter>
<ThemeProvider theme={theme}>
<Switch>
<Route exact path="/" component={LoginPage} />
<Route path="/authcallback" component={AuthCallback} />
<PrivateRoute path="/home" component={HomePage} />
</Switch>
</ThemeProvider>
</BrowserRouter>
</>
);
};
export default App;
This discussion helped me
My solution...
https://codesandbox.io/s/modest-fire-6mj3i?file=/src/PrivateRoute.tsx:0-517
import * as React from "react";
import { BrowserRouter, Link, Route, Switch } from "react-router-dom";
import PrivateRoute from "./PrivateRoute";
import "./styles.css";
const Home: React.FC = () => {
return <div>Home</div>;
};
const Login: React.FC = () => {
return <div>Login</div>;
};
export default function App() {
return (
<BrowserRouter>
<ul>
<li>
<Link to="/home">Home</Link>
</li>
<li>
<Link to="/">Login</Link>
</li>
</ul>
<Switch>
<Route exact path="/" component={Login} />
<PrivateRoute redirectPath="/login" path="/home" component={Home} />
</Switch>
</BrowserRouter>
);
}
import { Redirect, Route, RouteProps } from "react-router";
import React, { useState } from "react";
export interface IPrivateRouteProps extends RouteProps {
redirectPath: string;
}
const PrivateRoute: React.FC<IPrivateRouteProps> = (props) => {
const [isAuthenticated, setIsAuthenticated] = useState(false);
return isAuthenticated ? (
<Route {...props} component={props.component} render={undefined} />
) : (
<Redirect to={{ pathname: props.redirectPath }} />
);
};
export default PrivateRoute;
If I click Home I get redirected to /login and the Home component is hidden
useState is only used for testing the authenticated state from within the component.
Error is:
"Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object."
I dont see any mistakes, Appreciate your help!
import React, { lazy, Suspense } from "react";
import { BrowserRouter, Route, Switch } from "react-router-dom";
import NavWrapper from "./NavWrapper";
const Home = lazy(() => import("./Home"));
const Signin = lazy(() => import("./Signin"));
const App = () => {
const navWrapper = (component, props) => (
<NavWrapper component={component} {...props} />
);
return (
<div>
<BrowserRouter>
<Suspense fallback={<div>Loading...</div>}>
<Switch>
<Route path="/" component={Home} exact />
<Route
path="/signin"
component={props => navWrapper({ ...props }, Signin)}
exact
/>
</Switch>
</Suspense>
</BrowserRouter>
</div>
);
};
// .......in NavWrapper
import React, { Suspense } from "react";
const NavWrapper = ({ component: Component, ...props }) => {
return (
<div>
<h1>Testing</h1>
<Suspense fallback={<div>Test...</div>}>
<Component {...props} />
</Suspense>
</div>
);
};
export default NavWrapper;
//..in Signin
import React from "react";
const Signin = () => {
return <div>Testing</div>;
};
export default Signin;
This line:
component={props => navWrapper({ ...props }, Signin)}
should be:
component={props => navWrapper(Signin, { ...props })}
because your function declaration is:
const navWrapper = (component, props) => (...);
no?
You swapped the parameters of your navWrapper HOC function.
import React, { lazy, Suspense } from "react";
import { BrowserRouter, Route, Switch } from "react-router-dom";
import NavWrapper from "./NavWrapper";
const Home = lazy(() => import("./Home"));
const Signin = lazy(() => import("./Signin"));
const App = () => {
// Note the parameter order of navWrapper
const navWrapper = (component, props) => (
<NavWrapper component={component} {...props} />
);
return (
<div>
<BrowserRouter>
<Suspense fallback={<div>Loading...</div>}>
<Switch>
<Route path="/" component={Home} exact />
<Route
path="/signin"
component={props => navWrapper(Signin, { ...props })} // ensure parameters same order
exact
/>
</Switch>
</Suspense>
</BrowserRouter>
</div>
);
};