I had a very swell project going on in Next.js but I decided to revert back to Create React App yesterday and ran into some issues along the way.
I'm trying to keep a persistent layout along the app pages, that are separated from the pages themselves. Yet they appear on every route, even the auth pages, which have their own layout. "/" will either show the landing page that shouldn't contain the AppLayout or the home/feed page that should, if the user is authenticated. I'm unsure at what level I should be approaching this.
Another thing is that the user's profile data should only return on "/:username", instead of it loading on all of the pages with a param in the base URL "/". I'm making unnecessary graphql calls on /explore, /notifications, etc from that route. I'm not trying to change it to anything else such as, /u/:username and would rather find a solution that works for my case, even if that means replacing my router library for something else.
Any insight would be appreciated, this is /routes/Router.js:
import { Route, Switch } from "wouter";
import Login from './auth/Login'
import Signup from './auth/Signup'
import Verify from './auth/Verify'
import Reset from './auth/Reset'
import Root from './Root'
import Explore from './app/Explore'
import Notifications from './app/Notifications'
import Messages from './app/Messages'
import Bookmarks from './app/Bookmarks'
import Lists from './app/Lists'
import Profile from './app/Profile'
import Settings from './app/Settings'
import AppLayout from "../components/AppLayout";
export default function Router() {
return (
<>
<Route path="/i/flow/login" component={Login} />
<Route path="/i/flow/signup" component={Signup} />
<Route path="/i/verify/:token" component={Verify} />
<Route path="/i/flow/reset/:token" component={Reset} />
<Route path="/i/flow/reset" component={Reset} />
<Switch>
<AppLayout>
<Route path='/' component={Root} />
<Route path='/explore' component={Explore} />
<Route path='/notifications' component={Notifications} />
<Route path='/messages' component={Messages} />
<Route path='/bookmarks' component={Bookmarks} />
<Route path='/lists' component={Lists} />
<Route path='/settings' component={Settings} />
<Route exact path='/:username' component={Profile} />
</AppLayout>
</Switch>
</>
);
}
Sorry, wouter doesn't seem to include an exact attribute so I don't think that will make a difference.
Also, I'm pretty sure AppLayout will be rendered regardless of which route is active because it itself is not in a route.
Instead do something like this for each route where you'd like it to appear:
<Route path='/'>
<AppLayout>
<Root/>
</AppLayout>
</Route>
Regarding the '/:username' issue, is it rendering the profile route every time regardless of the path?
Related
I am using react-router in my project and using this.props.history.push() inside componentDidMount() if the user is not looged in ,then redirect him to Login component.
This is my code in App.js:
class App extends React.Component{
constructor(props){
super(props);
}
componentDidMount(){
firebase.auth().onAuthStateChanged((user)=>{
if(user){
this.props.dispatch(login(user.email));
}
else{
this.props.history.push('/login');
}
})
}
render(){
//console.log(this.props.isLoggedIn);
return (<div className="App">
<Switch>
<Route path="/" component={()=><Homepage userName={this.props.username} logout={this.logout}/>} />
<Route path="/login" component={Login} />
</Switch>
</div>);}
}
export default withRouter(connect(mapStateToProps)(App));
Below is my index.js code:
import React from 'react';
import ReactDOM from 'react-dom';
import 'bootstrap/dist/css/bootstrap.min.css';
import './index.css';
const store= createStore(combineReducers({userState: userState}),applyMiddleware(logger));
ReactDOM.render(
<Provider store={store}>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>
,
document.getElementById('root')
);
Please not that I have removed some unnecessary functions and imports irrelevent to the context of this question.
Now let us come to what I have tried till now:
Using Router instead of BrowserRouter with history object passed to it.
Tried removing switch but that didn't work too.
I also searched for other questions that address this problem but unfortunately, none of them worked for me.
Please help me to find if there is any issue in my code.
Thank You!!
EDIT:
Looks like I'm having a bad day, even Redirect isn't working for me!
I'm trying very hard but I don't understand why Login component is not being rendered even when the URL is being changed.
You need to use exact prop in your Route. Otherwise, /login will also match / first
<Route exact path="/" component={()=><Homepage userName={this.props.username} logout={this.logout}/>} />
<Route exact path="/login" component={Login} />
It seems like you didn't use exact in your Route component. If you don't use exact then react will route to / path first. It will reads the path(/login) as / + login.
If you provide exact to this / path then react will route to the specified component which exactly matches the path. It is not necessary to provide an exact to all the Route component.
It is necessary when:
For example,
<Route exact path="/" component={About} />
<Route path="/login" component={Login} />
Then you need to provide the exact to parent path.
<Route exact path="/login" component={Login} />
<Route path="/login/profile" component={Profile} />
In short, if your next Route component path is a child of the previous path then you need to provide the exact property to the parent path.
Edited: There is one more thing that I'd like to say that in your Route component of / path you must have a render prop instead of a component prop for rendering the Callback component like this.
<Route exact path="/" render={()=><Homepage userName={this.props.username} logout={this.logout}/>} />
Some credits to #Sohaib answer. I have added some more explanation to his answer.
I am using router version 5.2 and I am trying to make routes in file app.js.
My routes look like this:
import React from 'react';
import { render } from 'react-dom'; // if you use just render()
import ReactDOM from 'react-dom';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
ReactDOM.render(
<Router>
<div>
<Switch>
{/* Using the `component` prop */}
<Route exact path="/" component={Homepage} />
<Route path="/display-item" component={DisplayProduct} />
<Route path="/category/:id" component={DisplayCategory} />
<Route path="/product/:id" component={OneProduct} />
<Route path="/checkout" component={CheckOut} />
<Route path="/orderPlaced" component={OrderPlaced} />
</Switch>
</div>
</Router>,
document.getElementById('crud-app'),
);
Problem is that only route / is working. So only home page is displayed.
When I try to go to http://localhost:8000/#/display-item nothing happens. So I am still on homepage and I don't have any warnings or errors in console.
If I go to http://localhost:8000/display-item then I get error GET http://localhost:8000/display-item 404 (Not Found)
Please anyone had similar problem? How to solve this?
Thank you!
UPDATE:
The problem was with backend Laravel, beside routes in react, you should define routes in web.php file
Route::view('/', 'welcome');
Route::view('/display-item', 'welcome');
Place the home route as the last statement in switch then it will work. in your code every path matches with '/' so every time it will go to the home route.If you place it at the last then it will search for exact path.
I came across a problem which I dont know how to fix. I dont even know where to start.
The problem is next : I have url "localhost:4000/" If I will type url "localhost:4000/homepage" It will redirect me to my home page,But i want to restrict this access if token is not preserved.
Here are my routes :
import React from "react";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import LogIn from "./components/LogIn/Login";
import Register from "./components/Register/Register";
import Homepage from './components/HomePage/HomePage'
import Profile from './components/Profile/Profile'
import Posts from './components/addPostUI/Posts'
import "./app.css";
function App() {
return (
<Router>
<div className="App">
<Switch>
<Route path={"/"} exact component={LogIn} />
<Route path={"/login"} component={LogIn} />
<Route path={"/registration"} component={Register} />
<Route path={'/homepage'} component={Homepage} />
<Route path={'/profile'} component={Profile} />
<Route path={"/posts"} component={Posts} />
</Switch>
</div>
</Router>
);
}
export default App;
Any suggestions on how to restrict access and defend my routes?
There are many ways to restrict your Routes conditionally. The basic approach you can follow here is:
<Router>
<Switch>
<Route
path='/homepage'
render = {() => {
if(accessToken || localStorage.getItem('accessToken')) {
return <Homepage />;
} else {
return <Redirect to='/login' />;
}
}}
/>
</Switch>
</Router>
You can follow along with these steps whenever there is a need for conditional routing.
First determine what you want to authenticate users by, then you can do the following inside the page you want to protect, before the page renders.
if (failed access condition) return <Redirect to='/some route you want to redirect to' />
Be sure to import Redirect like this:
import { Redirect } from 'react-router-dom'
Also Consider
If you have a database, be sure to restrict access to the data based on the access token as well and don't depend on client side code to protect data.
I'm trying to build a React App, this is the first time i'm working with react and so i don't know how to troubleshoot this. Basically what i need is to create routes for a link, let's say these are the following links.
/car
/car/sedan
/car/coupe
i have setup routing as so.
car.js
import React from 'react'
import { BrowserRouter as Router, Switch, Route, Link } from 'react-router-dom'
import CoupeCar from './coupecar'
import SedanCar from './sedancar'
class Car extends React.Component {
constructor(props){
super(props);
}
render () {
return (
<div className="main_elem_container">
<Router>
<Switch>
<Route path="/car" component={Car} />
<Route exact path="/car/sedan" component={SedanCar} />
<Route exact path="/car/coupe" component={CoupeCar} />
</Switch>
</Router>
</div>
);
}
}
const Car = () => (
<p>I'm a Car</p>
)
export default Car;
And the routing works i can visit /car/sedan and /car/coupe when i'm browsing through the navigation from /car but i cannot visit /car/sedan when im at the /car/coupe page and vice-versa.
The navigation just gets stuck and doesn't load, please let me know on how i can fix this i've even tried many options but all of them give me this result, at least if i knew how to debug this it'll be better, thanks.
I don't know how your setup works partially, it should not with this config. What you need is:
<Router>
<Switch>
<Route exact path="/car" component={Car} />
<Route path="/car/sedan" component={SedanCar} />
<Route path="/car/coupe" component={CoupeCar} />
</Switch>
</Router>
So, if only when you hit /car your Car component renders. For /car/sedan and /car/coupe you will see the related components. If you don't use exact for /car, /car/sedan and /car/coupe will render Car component no matter what.
Also, do not use same component names. You have two Car components. Rename the container something else, App maybe?
try this, the exact path should be placed as last option
<Router>
<Switch>
<Route path="/car/sedan" component={SedanCar} />
<Route path="/car/coupe" component={CoupeCar} />
<Route exact path="/car" component={Car} />
</Switch>
</Router>
I'm new to React and React Router. I'm using React Router v4 and following a tutorial based on previous versions - but I made it work (using some stuff found on SO and some stuff on the react router v4 docs).
There is one thing though that is bothering me.
I have a url http://localhost:3000/#/bugs, which basically loads a list of all my bugs. But I also have possible urls like http://localhost:3000/#/bugs?priority=low&status=open which loads a specific set of urls.
The urls themselves work and do the job as expected.
The werid thing is that whenever I type http://localhost:3000/#/bugs?priority=low&status=open (or any params), the component do their jobs but the URL address bar shows http://localhost:3000/#/bugs (although the rendering shows everything related to priority and status shown).
Somehow, the URL location bar is changed but I don't understand why.
Here is my App.js
import React from 'react';
import ReactDOM from 'react-dom';
import {BugList} from './BugList';
import {Redirect} from 'react-router';
import {HashRouter as Router, Route} from 'react-router-dom';
const NoMatch = React.createClass({
render : function (){
return(
<h2>This path does not exist</h2>
);
}
});
ReactDOM.render(
(
<Router>
<div>
<Route path='/bugs' component={BugList}/>
<Route path='/bugs/priority/:priority' component={BugList}/>
<Redirect from='/' to="/bugs" />
<Route path="*" component={NoMatch} />
</div>
</Router>
),
document.getElementById('main')
);
Thanks in advance.
EDIT 12th of April. Despite of the precious help of someone below, this is still not solved. I tried using Switch inside a Router but it doesn't work at all (nothing is shown). So the problem is still happening, and this is the current state of my App.js, using react-15.5.3, react-dom-15.5.3, react-router-4.0.0 and react-router-dom-4.0.0....
import React from 'react';
import ReactDOM from 'react-dom';
import {BugList} from './BugList';
import BugEdit from './BugEdit';
import {Redirect} from 'react-router';
import {HashRouter as Router, Route} from 'react-router-dom';
const NoMatch = React.createClass({
render : function (){
return(
<h2>This path does not exist</h2>
);
}
});
ReactDOM.render(
(
<Router>
<div>
<Redirect from='/' to="/bugs" />
<Route path='/bugs' component={BugList}/>
<Route path='/bug/:id' component={BugEdit}/>
<Route path="*" component={NoMatch} />
</div>
</Router>
),
document.getElementById('main')
);
The problem is that even if you enter the URL with query this URL matches Redirect path (since it's just / any URL matches this pattern) so the redirection to /bugs occurs. You have to use Switch (remember to import it) to render only the first <Route> or <Redirect> that matches the URL:
<Router>
<Switch>
<Route path='/bugs' component={BugList}/>
<Redirect from='/' to="/bugs" />
...
</Switch>
</Router>
The problem occured only on page load and not on re-entering the URL because your routing is based on hashes and the browser doesn't reload page when only hash part changes.
Please note that Redirect component in React-Router v4 performs redirection only when it's rendered - it doesn't set up permanent redirection rule so in your case redirection works only on page load. If you'd like your app to always redirect given URL you'd have to define Route for URL you'd like to redirect from and render Redirect:
<Route path='/oldUrl' render={() => (
<Redirect to="newUrl" />
)}/>
Furthermore, React-Router v4 is quite different from v3 so I don't recommend using v3 tutorials - it doesn't make sense.
Building on what Bartek said: if you use Switch, it will go directional from top to bottom and render the first hit, since you moved your redirect to the first position it will always hit that first and then not go to the other routes. Which is why your Switch should look like this imho (untested):
<Router>
<Switch>
<Route path='/bugs' component={BugList}/>
<Route path='/bug/:id' component={BugEdit}/>
<Redirect from='/' to="/bugs" />
<Route path="*" component={NoMatch} />
</Switch>
</Router>
I know its 04/2020, but this will fix your issue.
<Switch>
<Route path='/bug/:id' component={BugEdit}/>
<Route path='/bugs' component={BugList}/>
<Redirect from='/' to="/bugs" />
<Route path="*" component={NoMatch} />
</Switch>
</Router>```