I am having problems dividing my application and using several routers. I have a main router where it handles several small applications and in each mini application I want to manage its opportune routes. What am I failing?
What I want to do is when I receive the data of the request, redirect me to a new screen but I can not get it. Can anybody help me? Thank you
Example https://stackblitz.com/edit/react-c2tkgf?file=Hello.js
Routes.js
import { BrowserRouter } from 'react-router-dom'
import React from 'react'
import { Switch, Route } from 'react-router-dom'
import { AuthenticatedRoute } from 'components/authenticated-route'
import Clients from 'components/clients'
import { Login } from 'components/login'
import Home from './Home/Home'
const Routes = () => {
return (
<BrowserRouter>
<Switch>
<Route exact path="/" component={Home} />} />
<Route exact path="/clients" component={Clients} />
<Route exact path="/login" component={Login} />} />
</Switch>
</BrowserRouter>
)
}
export default Routes
Clients.js
import React, { Component } from 'react'
import { connect } from 'react-redux'
import Dashboard from './Dashboard/Dashboard'
import { Redirect, Route, Switch } from 'react-router-dom'
class Clients extends Component {
render() {
return (
<div>
<SearchCustomers />
{this.props.customer.token ? (
<div>
<Switch>
<Route path={`/clients:${this.props.customer.id}/dashboard`} component={Dashboard} />
</Switch>
<Redirect to={`/clients:${this.props.customer.id}/dashboard`} />
</div>
) : null}
</div>
)
}
}
const mapStateToProps = state => {
return {
customer: state.customer,
}
}
export default connect(mapStateToProps)(Clients)
In your Routes component you have:
<Route exact path="/clients" component={Clients} />
<Route exact path="/login" component={Login} />} />
since you have exact on there, those components will only be rendered when at exactly /clients or /login. in your built components, once you change the path, your parent component no longer renders, therefore nothing inside those components will render. remove the exact from your Routes:
<Rout path="/clients" component={Clients} />
<Rout path="/login" component={Login} />} />
Related
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
Hello guys. I noticed one react-router problem while testing my project. There is a link which takes me to the product categories http://localhost:3000/category. It works fine but when I click a couple of times it looks like it takes there a couple of times as well. And when I press the go back button in Google Chrome it takes me that link again cause it was clicked on several times. How to prevent it?
import React from 'react';
import { BrowserRouter as Router,Route } from 'react-router-dom';
import { Container } from 'react-bootstrap';
import Header from './components/Header';
import Footer from './components/Footer';
import HomeScreen from './screens/HomeScreen';
import LoginScreen from './screens/LoginScreen';
import RegisterScreen from './screens/RegisterScreen';
import ProductScreen from './screens/ProductScreen';
import CartScreen from './screens/CartScreen';
import ProfileScreen from './screens/ProfileScreen';
import ShippingScreen from './screens/ShippingScreen';
import PaymentScreen from './screens/PaymentScreen';
import PlaceOrderScreen from './screens/PlaceOrderScreen';
import OrderScreen from './screens/OrderScreen';
import UserListScreen from './screens/UserListScreen';
import OrderListScreen from './screens/OrderListScreen';
import UserEditScreen from './screens/UserEditScreen';
import ProductEditScreen from './screens/ProductEditScreen';
import ProductListScreen from './screens/ProductListScreen';
import Powders from './screens/categories/Powders';
import Deodorants from './screens/categories/Deodorants';
import Soaps from './screens/categories/Soaps';
import Shampoos from './screens/categories/Shampoos';
import Papers from './screens/categories/Papers';
import Category from './screens/Category';
const App = () => {
return (
<Router>
<Header/>
<main className="py-3">
<Container>
<Route path="/" component={HomeScreen} exact />
<Route path="/page/:pageNumber" component={HomeScreen} exact />
<Route path="/search/:keyword/page/:pageNumber" component={HomeScreen} />
<Route path="/search/:keyword" component={HomeScreen} exact />
<Route path="/login" component={LoginScreen} />
<Route path="/shipping" component={ShippingScreen} />
<Route path="/placeorder" component={PlaceOrderScreen} />
<Route path="/order/:id" component={OrderScreen} />
<Route path="/payment" component={PaymentScreen} />
<Route path="/register" component={RegisterScreen} />
<Route path="/profile" component={ProfileScreen} />
<Route path="/admin/userlist" component={UserListScreen} />
<Route path="/admin/orderlist" component={OrderListScreen} />
<Route path="/admin/productlist" component={ProductListScreen} exact />
<Route path="/admin/productlist/:pageNumber" component={ProductListScreen} exact />
<Route path="/admin/user/:id/edit" component={UserEditScreen} />
<Route path="/admin/product/:id/edit" component={ProductEditScreen} />
<Route path="/product/:id" component={ProductScreen} />
<Route path="/cart/:id?" component={CartScreen} />
<Route path="/category/powders" component={Powders} />
<Route path="/category/deodorants" component={Deodorants} />
<Route path="/category/soaps" component={Soaps} />
<Route path="/category/shampoos" component={Shampoos} />
<Route path="/category/papers" component={Papers} />
<Route path="/category" component={Category} exact />
</Container>
</main>
<Footer/>
</Router>
);
}
export default App;
Turns out this is something a lot more people have raised questions about. I have faced it a number of times myself.
my work around solution would be to use <Link > instead since that is built to act like the HTML's <a > component.
Another method would be for you to use the history.block.
import { useHistory } from "react-router-dom";
import { useEffect } from "react";
export function useLocationBlocker() {
const history = useHistory();
useEffect(
() =>
history.block(
(location, action) =>
action !== "PUSH" ||
getLocationId(location) !== getLocationId(history.location)
),
[] // eslint-disable-line react-hooks/exhaustive-deps
);
}
function getLocationId({ pathname, search, hash }) {
return pathname + (search ? "?" + search : "") + (hash ? "#" + hash : "");
}
Or this other solution here. It will just check and ensure history is not repeated (Pun intended);
props.history.listen(location => {
lastLocation = location
})
// monkey patching to prevent pushing same url into history stack
const prevHistoryPush = props.history.push
props.history.push = (pathname, state = {}) => {
if (lastLocation === null ||
pathname !== lastLocation.pathname + lastLocation.search + lastLocation.hash ||
JSON.stringify(state) !== JSON.stringify(lastLocation.state)
) {
prevHistoryPush(pathname, state)
}
}
check out this few threads for clarity and some details;
https://github.com/ReactTraining/react-router/issues/5362
https://github.com/ReactTraining/history/issues/470#issuecomment-363449663
I am developing a system with a login, and I want the drawer to appear only on routes that are private. How can I do that, below is a code that I already tried and was not successful.
import React from "react";
import { BrowserRouter as Router, Route } from "react-router-dom";
import Home from "./Home";
import Login from "./Login";
import Details from "./Details";
import { AuthProvider } from "./Auth";
import PrivateRoute from "./PrivateRoute";
import Drawer from "./components/Drawer";
const App = () => {
return (
<AuthProvider>
<Router>
<Route exact path="/login" component={Login} />
</Router>
<Router>
<RoutePrivate />
</Router>
</AuthProvider>
);
};
const RoutePrivate = () => {
return (
<Router>
<Drawer />
<PrivateRoute exact path="/" component={Home} />
<PrivateRoute exact path="/:id" component={Details} />
</Router>
);
};
export default App;
You could do conditional rendering of drawer
const RoutePrivate = () => {
return (
<Router>
{window.location.pathname !== '/login' ? <Drawer /> : null}
<PrivateRoute exact path="/" component={Home} />
<PrivateRoute exact path="/:id" component={Details} />
</Router>
);
};
Good luck
You can go with few options.
you can remove <Drawer /> from router and render it inside <PrivateRoute /> along with matched router component (Home or Details etc).
Inside Drawer component, you can check auth and render null if auth failed. This way public routes will never get to see Drawer compoennt.
create a common layout and put the router inside layout. Check this. Also I got a random codesandbox (not fully working) but you can see the code reference there.
I'm building a multilingual site in React and I'm using react router for my routing. Right now I have it setup where the prefix has to be present in order to transition to the route.
What I'm trying to do is the following: When I go to localhost:3000 I want my app to transition to the home component. And when I go to
localhost:3000/jp I still want to transition to the home component except now my language prefix would be jp.
I want English to be the default language and for other languages they have to be present in the prefix.
Right now it only transitions to the home component if I enter localhost:3000/en.
Is there a way to accomplish this?
import React, { Component } from 'react';
import { Route, Switch } from "react-router-dom";
import { Home } from '../containers/home';
import { About } from '../containers/about';
import { Contact } from '../containers/contact';
export default class Routes extends Component {
render(){
return(
<Switch>
<Route path="/:lang/about" component={About} />
<Route path="/:lang/contact" component={Contact} />
<Route path="/:lang/" component={Home} />
</Switch>
);
}
}
Just add a Redirect at the end which will be matched when nothing else does and it will redirect to the /en
import React, { Component } from 'react';
import { Route, Switch, Redirect } from "react-router-dom";
import { Home } from '../containers/home';
import { About } from '../containers/about';
import { Contact } from '../containers/contact';
export default class Routes extends Component {
render(){
return(
<Switch>
<Route path="/:lang/about" component={About} />
<Route path="/:lang/contact" component={Contact} />
<Route path="/:lang/" component={Home} />
<Redirect to="/en" />
</Switch>
);
}
}
Demo at https://codesandbox.io/s/18rm8k82lj
Updated answer (due to comment)
The problem is that the /:lang/ will match /about and the lang will be set to about.
A solution is to use the render prop of the route and decide what you want to do there
export default class Routes extends Component {
render() {
const supportedLanguages = ["en", "jp", "de", "es"];
return (
<Switch>
<Route path="/:lang/about" component={About} />
<Route path="/:lang/contact" component={Contact} />
<Route
path="/:lang/"
render={props =>
supportedLanguages.includes(props.match.params.lang) ? (
<Home {...props} />
) : (
<Redirect to={`/en/${props.match.params.lang}`} />
)
}
/>
</Switch>
);
}
}
Demo at https://codesandbox.io/s/k2n9997345
I've recently started playing around with Redux and quickly came across this error message : Warning: You cannot change <Router routes>; it will be ignored (I'm also using react-router). After a little search, I understood I had to declare my routes in a variable so they wouldn't get re-rendered.
So here's my code :
Routing.js
import React from 'react';
import { Router, browserHistory, Route, IndexRoute, Redirect } from 'react-router';
import { syncHistoryWithStore } from 'react-router-redux';
import RouterUtils from 'src/utils/js/RouterUtils';
import MainContent from 'src/common/main-content/js/MainContent';
// modules loaded lazily
import IndexPage from 'src/views/index/js/IndexPage';
import Page403 from 'src/views/403/js/403';
import Page404 from 'src/views/404/js/404';
import LoginPage from 'src/views/login/js/LoginPage';
import GetBusiness from 'src/route-fetch-components/business-get/js/GetBusiness';
import BusinessesPage from 'src/views/businesses-list/js/BusinessesPage';
import BusinessPage from 'src/views/business-details/js/BusinessPage';
import GetJobSeeker from 'src/route-fetch-components/jobseeker-get/js/GetJobSeeker';
import JobSeekersPage from 'src/views/jobseekers-list/js/JobSeekersPage';
import JobSeekerPage from 'src/views/jobseeker-details/js/JobSeekerPage';
import GetJobOffer from 'src/route-fetch-components/job-offer-get/js/GetJobOffer';
import JobOffersPage from 'src/views/job-offers-list/js/JobOffersPage';
import JobOfferPage from 'src/views/job-offer-details/js/JobOfferPage.js';
import JobOfferCreatePage from 'src/views/job-offer-create/js/JobOfferCreatePage';
const lazyLoadComponent = lazyModule =>
(location, cb) => {
lazyModule(module => {
cb(null, module.default);
});
};
const redirectTo404 = () => {
RouterUtils.redirect('/404');
};
const routes = (
<div>
<Route path="/" component={MainContent}>
<IndexRoute getComponent={lazyLoadComponent(IndexPage)} />
<Route path="businesses">
<IndexRoute getComponent={lazyLoadComponent(BusinessesPage)} />
<Route path=":user_id" getComponent={lazyLoadComponent(GetBusiness)}>
<IndexRoute getComponent={lazyLoadComponent(BusinessPage)} />
<Route path="job-offers">
<IndexRoute onEnter={() => redirectTo404()} /> // TODO: Add a component to list all job offers related to a business
<Route path=":job_offer_id" getComponent={lazyLoadComponent(GetJobOffer)}>
<IndexRoute getComponent={lazyLoadComponent(JobOfferPage)} />
</Route>
</Route>
</Route>
</Route>
<Route path="jobseekers">
<IndexRoute getComponent={lazyLoadComponent(JobSeekersPage)} />
<Route path=":user_id" getComponent={lazyLoadComponent(GetJobSeeker)}>
<IndexRoute getComponent={lazyLoadComponent(JobSeekerPage)} />
/*<Route path="applications">
<IndexRoute onEnter={() => redirectTo404()} /> // TODO: Add a component to list all applications related to a jobseeker
<Route path=":application_id" getComponent={lazyLoadComponent(JobOfferPage)} />
</Route>*/
</Route>
</Route>
<Route path="job-offers">
<IndexRoute getComponent={lazyLoadComponent(JobOffersPage)} />
<Route path="create" getComponent={lazyLoadComponent(JobOfferCreatePage)} />
</Route>
<Route path="403" getComponent={lazyLoadComponent(Page403)} />
<Route path="404" getComponent={lazyLoadComponent(Page404)} />
</Route>
<Route path="login" getComponent={lazyLoadComponent(LoginPage)} />
<Redirect from="*" to="404" />
</div>);
export default class Routing extends React.Component {
constructor(props, context) {
super(props);
this.history = syncHistoryWithStore(browserHistory, context.store);
}
render() {
return (
<Router history={this.history}>
{routes}
</Router>
);
}
}
Routing.contextTypes = {
store: React.PropTypes.object.isRequired,
};
It works perfectly fine, but I would now like to make a component ouf of my routes. So I just take the JSX code out in a new component :
Routing.js
import React from 'react';
import { Router, browserHistory } from 'react-router';
import { syncHistoryWithStore } from 'react-router-redux';
import Routes from './Routes';
const routes = <Routes />;
export default class Routing extends React.Component {
constructor(props, context) {
super(props);
this.history = syncHistoryWithStore(browserHistory, context.store);
}
render() {
return (
<Router history={this.history}>
{routes}
</Router>
);
}
}
Routing.contextTypes = {
store: React.PropTypes.object.isRequired,
};
Routes.js
import React from 'react';
import { Route, IndexRoute, Redirect } from 'react-router';
import RouterUtils from 'src/utils/js/RouterUtils';
import MainContent from 'src/common/main-content/js/MainContent';
// components loaded lazily
import IndexPage from 'src/views/index/js/IndexPage';
import Page403 from 'src/views/403/js/403';
import Page404 from 'src/views/404/js/404';
import LoginPage from 'src/views/login/js/LoginPage';
import GetBusiness from 'src/route-fetch-components/business-get/js/GetBusiness';
import BusinessesPage from 'src/views/businesses-list/js/BusinessesPage';
import BusinessPage from 'src/views/business-details/js/BusinessPage';
import GetJobSeeker from 'src/route-fetch-components/jobseeker-get/js/GetJobSeeker';
import JobSeekersPage from 'src/views/jobseekers-list/js/JobSeekersPage';
import JobSeekerPage from 'src/views/jobseeker-details/js/JobSeekerPage';
import GetJobOffer from 'src/route-fetch-components/job-offer-get/js/GetJobOffer';
import JobOffersPage from 'src/views/job-offers-list/js/JobOffersPage';
import JobOfferPage from 'src/views/job-offer-details/js/JobOfferPage.js';
import JobOfferCreatePage from 'src/views/job-offer-create/js/JobOfferCreatePage';
const lazyLoadComponent = lazyModule =>
(location, cb) => {
lazyModule(module => {
cb(null, module.default);
});
};
const redirectTo404 = () => {
RouterUtils.redirect('/404');
};
const Routes = () => (
<div>
<Route path="/" component={MainContent}>
<IndexRoute getComponent={lazyLoadComponent(IndexPage)} />
<Route path="businesses">
<IndexRoute getComponent={lazyLoadComponent(BusinessesPage)} />
<Route path=":user_id" getComponent={lazyLoadComponent(GetBusiness)}>
<IndexRoute getComponent={lazyLoadComponent(BusinessPage)} />
<Route path="job-offers">
<IndexRoute onEnter={() => redirectTo404()} /> // TODO: Add a component to list all job offers related to a business
<Route path=":job_offer_id" getComponent={lazyLoadComponent(GetJobOffer)}>
<IndexRoute getComponent={lazyLoadComponent(JobOfferPage)} />
</Route>
</Route>
</Route>
</Route>
<Route path="jobseekers">
<IndexRoute getComponent={lazyLoadComponent(JobSeekersPage)} />
<Route path=":user_id" getComponent={lazyLoadComponent(GetJobSeeker)}>
<IndexRoute getComponent={lazyLoadComponent(JobSeekerPage)} />
/*<Route path="applications">
<IndexRoute onEnter={() => redirectTo404()} /> // TODO: Add a component to list all applications related to a jobseeker
<Route path=":application_id" getComponent={lazyLoadComponent(JobOfferPage)} />
</Route>*/
</Route>
</Route>
<Route path="job-offers">
<IndexRoute getComponent={lazyLoadComponent(JobOffersPage)} />
<Route path="create" getComponent={lazyLoadComponent(JobOfferCreatePage)} />
</Route>
<Route path="403" getComponent={lazyLoadComponent(Page403)} />
<Route path="404" getComponent={lazyLoadComponent(Page404)} />
</Route>
<Route path="login" getComponent={lazyLoadComponent(LoginPage)} />
<Redirect from="*" to="404" />
</div>
);
export default Routes;
Ahhhhh... Cleaner. Except it doesn't work anymore. My page doesn't load, and I get this error :
Warning: [react-router] Location "/" did not match any routes
Now I'm wondering : what's the difference between assigning my JSX code to a var, as const routes = (<div>...</div>) and declaring it in a React Component (actually a pure function here, but I tested both)?
Thanks in advance for your time!