React Router Link is Showing Two Components - javascript

I didn't know the best way to describe this issue, but I'm going to try and explain as best I can.
In my core React App component, i'm doing a conditional render, based on if a user is logged in.
If Logged In --- I show the main page, and if not, they get the login screen.
On my login page, i'm trying to put in a link at the bottom which directs a user to signup for a new account. My issue that when I click to this 'newuser' page, it is rendering both my login form and the create user form, both different components (see below).
I suspect this is an issue with how I have my react router setup, but I'm not sure what the problem is.
Here is the code in my App component.
<Container>
<Router>
<Notification />
{props.loggedUser ? (
<div>
<Navbar />
<Route exact path="/" render={() => <Blogs />} />
<Route exact path="/blogs" render={() => <Blogs />} />
<Route path="/login" render={() => <Login />} />
<Route
exact
path="/blogs/:id"
render={({ match }) => (
<Blog
blog={blogById(match.params.id)}
user={props.loggedUser}
/>
)}
/>
<Route exact path="/users" render={() => <Users />} />
<Route
exact
path="/users/:id"
render={({ match }) => <User user={userById(match.params.id)} />}
/>
</div>
) : (
<>
<Login />
</>
)}
</Router>
<div>
<br />
<em>Blog app, John 2019</em>
</div>
</Container>
And here is my Login component. I've tried including the route for the new users page on both sides of the conditional statement above and then also in the Login Form below, as I have now. All are leading to the same issue.
<h1>Login To Blog Application</h1>
<Form onSubmit={handleLogin}>
<Form.Field>
<label>username</label>
<input {...username.omitreset} name="username" />
</Form.Field>
<Form.Field>
<label>password</label>
<input {...password.omitreset} type="password" />
</Form.Field>
<Button type="submit">login</Button>
<div>
<br />
<Link to="/newuser">or signup to become a new user</Link>
<Route path="/newuser" render={() => <NewUser />} />
</div>
</Form>
</>
and NewUser component
import React from "react";
import { connect } from "react-redux";
import { createUser } from "../reducers/userReducer";
import { setNotification } from "../reducers/notificationReducer";
import { Form, Button } from "semantic-ui-react";
const NewUser = props => {
const addUser = event => {
event.preventDefault();
const userObject = {
username: event.target.username.value,
name: event.target.name.value,
password: event.target.password.value
};
event.target.username.value = "";
event.target.name.value = "";
event.target.password.value = "";
props.createUser(userObject);
};
return (
<>
<h1>Create a New Blog Account</h1>
<Form onSubmit={addUser}>
<Form.Field>
<label>username</label>
<input {...props.username} name="username" />
</Form.Field>
<Form.Field>
<label>name</label>
<input {...props.name} type="password" />
</Form.Field>
<Form.Field>
<label>password</label>
<input {...props.password} type="password" />
</Form.Field>
<Button type="submit">login</Button>
</Form>
</>
);
};
const mapDispatchToProps = {
createUser,
setNotification
};
export default connect(null, mapDispatchToProps)(NewUser);

you shouldn't do conditional rendering, because when the user is not logged the Loggin component is rendered and is not depended on the path at all. then you change the path by clicking Link to="/newuser" and the Sign up renders inside

I got this working based on det2dachoppa's recommendations. Removed the conditional and added the Switch and redirects to ensure that a user can't view the pages without logging in.
<Router>
<Notification />
<div>
<Navbar />
<Switch>
{props.loggedUser && (
<React.Fragment>
<Route exact path="/">
<Blogs />
</Route>
</React.Fragment>
)}
{props.loggedUser && (
<React.Fragment>
<Route exact path="/blogs">
<Blogs />
</Route>
</React.Fragment>
)}
{props.loggedUser && (
<React.Fragment>
<Route
exact
path="/blogs/:id"
render={({ match }) => (
<Blog
blog={blogById(match.params.id)}
user={props.loggedUser}
history={props.history}
/>
)}
/>
</React.Fragment>
)}
{props.loggedUser && (
<React.Fragment>
<Route exact path="/users">
<Users />
</Route>
</React.Fragment>
)}
{props.loggedUser && (
<React.Fragment>
<Route
exact
path="/users:id "
render={({ match }) => (
<User user={userById(match.params.id)} />
)}
/>
</React.Fragment>
)}
{props.loggedUser && (
<React.Fragment>
<Route exact path="/newblog">
<NewBlog />
</Route>
</React.Fragment>
)}
<Route path="/login">
<Login />
</Route>
<Route path="/newuser">
<NewUser />
</Route>
<Redirect to="/login">
<Login />
</Redirect>
</Switch>
</div>
</Router>

Related

React webpage refreshing every 4-6 seconds

I'm not really sure even what part of my code to show because it's such a general error, but everytime I npm start my React webpage it automatically goes from the home page to the authentication dashboard and starts refreshing.
I'm guessing it's a problem with React Router but I'm not really sure about this either?
This is how my App.js App component currently looks, which has the main Route functionality.
const App = () => {
const [auth, setAuth] = useState(false);
useEffect(() => {
localStorage.setItem("user", auth);
}, [auth]);
return (
<div className="landing" style={{zIndex:0, margin:"0px", position:"fixed"}}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
{!auth && (
<Route
path="/auth"
element={
<Auth authenticate={(val) => setAuth(val === 1 ? true : false)} />
}
/>
)}
{auth && (
<>
<Route path="/dashboard" element={<Dashboard />} />
</>
)}
<Route
path="*"
element={<Navigate to={auth ? "/dashboard" : "/auth"} />}
/>
</Routes>
</div>
);
}
And this is how my Home.js Home component file looks like
function Home() {
return (
<div className="main">
<div className="landingImageDiv">
<img src={ligaLogo} alt="uchisvg" className="landingImage" />
<div id="fade" className="linkDiv topMargin5">
<div>
<Link to="/about" className="popupLink">
<span className="hover">[About]</span>
</Link>
</div>
<div>
<Link to="/auth" className="popupLink">
<span className="hover">[Talent Network]</span>
</Link>
</div>
<div>
{/* Format to request access to platform */}
<a href="https://forms.gle/vKzq5M9n56oKKV5DA" className="popupLink">
<span className="hover">[Request RSO Onboarding]</span>
</a>
</div>
</div>
</div>
<div className="landing" id="fade">
<div style={{ zIndex: 5, position: "relative" }}></div>
</div>
</div>
);
}
Change your route definition as follows:
{
!auth ? (
<Route
path="/auth"
element={
<Auth authenticate={(val) => setAuth(val === 1 ? true : false)} />
}
/>
) : (
<>
<Route path="/dashboard" element={<Dashboard />} />
</>
);
}

No routes matching location "/dash/1"

I have the following problem. my route is not registered and i dont know why.
Links
dashboard.jsx
this code generates all the links.
<div className="flex w-3/4 m-auto flex-col mt-10 xl:w-1/2">
{questions.map(({ id, question }) => {
return (
<Link to={`/dash/${id}`}>
<QuestionHeader question={question} />
</Link>
);
})}
</div>
/dash/1,/dash/2,.... are generated by the map function above.
i have two files that represent the routes.
NavRoutes
const NavRoutes = () => {
return (
<Routes>
<Route path="/:id" element={<Question />} />
<Route path="" element={<Dashboard />} />
</Routes>
);
};
export default NavRoutes;
here is the Main component
const Main = () => {
return (
<div>
<NavBar />
<NavRoutes />
<Footer />
</div>
);
};
export default Main;
and the main routes for authentication and accessing the main page
const App = () => {
let { user } = useAuthContext();
return (
<div className="w-full bg-slate-700 block fixed h-full">
<Header />
<Router>
<Routes>
<Route
path="/dash"
element={!user ? <Navigate to="/auth" /> : <Main />}
>
</Route>
<Route path="" element={<Login />} />
</Routes>
</Router>
</div>
);
};
when i try to access /dash/1, i get the following error
router.ts:11 No routes matched location "/dash/1"
Did you try the following in your NavRoutes (prepending '/dash' to '/:id'):
<Route path="/dash/:id" element={<Question />} />
i solved this by doing the following
const App = () => {
let { user } = useAuthContext();
return (
<div className="w-full bg-slate-700 block fixed h-full">
<Header />
<Router>
<Routes>
<Route
path="/dash/*"
element={!user ? <Navigate to="/auth" /> : <Main />}
>
</Route>
<Route path="/auth" element={<Login />} />
</Routes>
</Router>
</div>
);
};
you need to include a * when nesting deeper

Nested routes in react-router-dom

enter image description here
How to navigate through the tabs in react.
Since I am currently in a tab, I have already used react route and the nested route does not work. how to make a transition through the masonry. Through a nested route or otherwise?
I have a react application inside this I have component with my routers
export const Container = (props) => {
return (
<Switch>
<Route exact path="/">
<Redirect to={PERSONAL} />
</Route>
<Route path={PAGE} render={() => <PicturesMainPage />} />
<Route path={PERSONAL} render={() => <PersonalPage />} />
<Route path={PERSONAL_SETTINGS} render={() => <PersonalSettingsPage />} />
</Switch>
);
};
In this component I have inside this component I drow an information about user with menu and i wand to drow athother components for click in to menu
export const PersonalPage = () => {
return (
<div className="container">
<PersonalInfo />
<div className="personal-area__galery">
<Switch>
<Route exact path={PERSONAL}>
<Redirect to={PERSONAL_GALLERY} />
</Route>
<Route path={PERSONAL_GALLERY} render={() => <Gallery images={images} />} />
<Route path={PERSONAL_COLLECTIONS} render={() => <Collections />} />
<Route path={PERSONAL_STATISTICS} render={() => <Statistics />} />
</Switch>
</div>
</div>
);
};
Person info
let menu = [
{ href: PERSONAL_GALLERY, text: 'Галерея' },
{ href: PERSONAL_COLLECTIONS, text: 'Коллекции' },
{ href: '/personal/statistics', text: 'Статистика' },
];
let person = {
profileName: 'Top Waifu',
profileTag: '#topwaifu',
profileDescription: 'Самая топовая вайфу твоего района',
subscribers: '5.1m',
subscriptions: 246,
};
export const PersonalInfo = (props) => {
return (
<div>
<div className="personal-area__profile">
<div className="personal-area__profile__description">
<PersonalAvatar img={'assets/img/testImg4.png'} />
<PersonalDescription
profileName={person.profileName}
profileTag={person.profileTag}
profileDescription={person.profileDescription}
subscribers={person.subscribers}
subscriptions={person.subscriptions}
/>
<div className="personal-area__profile__description__icons">
<Share />
<Settings />
<MoreOptions />
</div>
</div>
</div>
<div className="personal-area__menu">
<ul>
{menu.map((elem, i) => (
<MenuElement key={i} menulink={elem.href} menuName={elem.text} />
))}
</ul>
</div>
</div>
);
};
take a look at this codesandbox I made.
https://codesandbox.io/s/frosty-cdn-1fn0u?file=/src/App.js
Here you can see a clear example of nesting routes.

How to hide nav if user is not logged in react

Route.js
const Layout = () => {
const SecuredRoute = ({ ...props }) => (
console.log(props.path),
<Route path={props.path} render={(data) => (
console.log(data),
localStorage.getItem('accessToken')
? <props.render {...data} />
: <Redirect to='/login' />
)} />
)
return (
<>
<BrowserRouter>
<Navbar /> // It needs to be hidden if user is not logged in
<div className='layout'>
<Switch>
<Route exact path='/home' component={Home} />
<Route exact path='/login' component={Login} />
<SecuredRoute exact path='/about' component={About} />
<Route exact path='/contact' component={Contact} />
<Route exact path='/add' component={AddBlog} />
<Route exact path='/edit/:id' component={UpdateBlog} />
<Route exact path='/blog/:id' component={Blogdetail} />
<Route component={Home} />
</Switch>
</div>
<Footer />
</BrowserRouter>
</>
)
}
export default Layout
I want if the user is not logged in then navbar must be hidden. It means when route = '/login' navbar needs to be hidden. u have tried out many things but nothing works. I am new to React. Any help will be appreciated?
You can create a boolean variable and short-circuit it.
render() {
const visible = true;
const notVisible = false;
return (
<div>
{visible && <p>I am visible</p>}
{notVisible && <p>I am not visible</p>}
</div>
);
}
Try this in the Navbar component my friend:
const [loggedIn, setLoggedIn] = useState(false);
const Layout = () => {
const SecuredRoute = ({ ...props }) => (
console.log(props.path),
<Route path={props.path} render={(data) => (
console.log(data),
localStorage.getItem('accessToken')
? <props.render {...data} />
: <Redirect to='/login' />
)} />
)
return (
<>
<BrowserRouter>
<Navbar loggedIn={loggedIn} /> // It needs to be hidden if user is not logged in
<div className='layout'>
<Switch>
<Route exact path='/home' component={Home} />
<Route exact path='/login' component={() => <Login setLoggedIn={setLoggedIn} />} />
<SecuredRoute exact path='/about' component={About} />
<Route exact path='/contact' component={Contact} />
<Route exact path='/add' component={AddBlog} />
<Route exact path='/edit/:id' component={UpdateBlog} />
<Route exact path='/blog/:id' component={Blogdetail} />
<Route component={Home} />
</Switch>
</div>
<Footer />
</BrowserRouter>
</>
)
}
export default Layout
I gave a setState to login component. You give a true boolean when the user logs in, loggedIn(true) and the parent state changes.
And in the Navbar component:
return(
loggedIn
?
//The Body of NavBar
:
""
}
)

ReactJs Problem with displaying home page after user logs-in

I am using passport.js and jwt token to handle the user authentication state in my react app. After the user logs-in, I store the token in localStorage and so depending on whether there's a token or not in the localStorage, I will updated the isAuthenticated state property.
Now, when a guest user (non-authenticated) user, opens the app, he should not be able to access the home-page of the app.
So I devided the routes that the guest user can access and the authenticated user can access to two different variable guestLinks and authLinks.
And depending on the isAuthenticated property, I will display one of those.
App.js
class App extends Component {
render() {
const authLinks = (
<Switch>
<Route
exact
path="/"
name="Login Page"
render={props => <Login {...props} />}
/>
<Route
exact
path="/404"
name="Page 404"
render={props => <Page404 {...props} />}
/>
<Route
exact
path="/500"
name="Page 500"
render={props => <Page500 {...props} />}
/>
<Route
path="/home"
name="Home"
render={props => <DefaultLayout {...props} />}
/>
</Switch>
);
const guestLinks = (
<Switch>
<Route
exact
path="/"
name="Login Page"
render={props => <Login {...props} />}
/>
<Route
exact
path="/register"
name="Register Page"
render={props => <Register {...props} />}
/>
<Route
exact
path="/404"
name="Page 404"
render={props => <Page404 {...props} />}
/>
<Route
exact
path="/500"
name="Page 500"
render={props => <Page500 {...props} />}
/>
</Switch>
);
const currentState = store.getState();
console.log(
"currentState.auth.isAuthenticated: ",
currentState.auth.isAuthenticated
);
return (
<Provider store={store}>
<HashRouter>
<React.Suspense fallback={loading()}>
{console.log(currentState.auth.isAuthenticated)}
{/* TODO: Not sure if this always works. If after the user logsin he gets a blank page and he has to reload to be redirected to home then
this way of routing may need to modified */}
{currentState.auth.isAuthenticated ? authLinks : guestLinks}
</React.Suspense>
</HashRouter>
</Provider>
);
}
}
Notice this line:
{currentState.auth.isAuthenticated ? authLinks : guestLinks}
So after the user logs in, (so he is authenticated), he is redirected to the home-page:
class Login extends Component {
constructor() {
super();
this.state = {
email: "",
mot_de_passe: "",
errors: ""
};
this.onChange = this.onChange.bind(this);
this.onSubmit = this.onSubmit.bind(this);
}
componentDidMount() {
// If the user has already logged-in and he attempts to access the login page this will redirect him to home
if (this.props.auth.isAuthenticated) {
this.props.history.push("/home");
}
}
//This runs when the component receives new properties
componentWillReceiveProps(nextProps) {
// After the user has logged-in this will redirect him to home
if (nextProps.auth.isAuthenticated) {
this.props.history.push("/home");
}
if (nextProps.errors) {
this.setState({ errors: nextProps });
}
}
onChange(e) {
this.setState({
[e.target.name]: e.target.value
});
}
onSubmit(e) {
console.log(e);
// Since it's a form, we don't want it to have its default behavior
e.preventDefault();
const userInfo = {
email: this.state.email,
password: this.state.mot_de_passe
};
// Any action that we bring-in is going to be stored inside props
//this.props.loginUser(userInfo, this.props.history);
this.props.loginUser(userInfo);
}
render() {
return (
<div className="app flex-row align-items-center">
<Container>
<Row className="justify-content-center">
<Col md="8">
<CardGroup>
<Card className="p-4">
<CardBody>
<Form noValidate onSubmit={this.onSubmit}>
<h1>Se connecter</h1>
<p className="text-muted">
Connectez-vous à votre compte
</p>
<InputGroup className="mb-3">
<InputGroupAddon addonType="prepend">
<InputGroupText>
<i className="icon-user"></i>
</InputGroupText>
</InputGroupAddon>
{/* WORK_HERE */}
<Input
name="email"
type="text"
placeholder="Email"
value={this.state.email}
onChange={this.onChange}
/>
</InputGroup>
<InputGroup className="mb-4">
<InputGroupAddon addonType="prepend">
<InputGroupText>
<i className="icon-lock"></i>
</InputGroupText>
</InputGroupAddon>
<Input
name="mot_de_passe"
type="password"
placeholder="Mot de passe"
autoComplete="current-password"
value={this.state.mot_de_passe}
onChange={this.onChange}
/>
</InputGroup>
<Row>
<Col xs="6">
<Button color="primary" className="px-4">
Se connecter
</Button>
</Col>
<Col xs="6" className="text-right">
<Button color="link" className="px-0">
Mot de passe oubliée?
</Button>
</Col>
</Row>
</Form>
</CardBody>
</Card>
<Card
className="text-white bg-primary py-5 d-md-down-none"
style={{ width: "44%" }}
>
<CardBody className="text-center">
<div>
<h2>Bienvenue au Viwone SAV</h2>
<p>
Suivez en temps réel l'évolution des opérations du
service après-vente.
</p>
</div>
</CardBody>
</Card>
</CardGroup>
</Col>
</Row>
</Container>
</div>
);
}
}
The problem is that after he logs-in, he get a blank screen and he has to reload the page in order for the home-page to be successfully displayed.
It seems that the authLinks don't get loaded fast enough for the app to be able to detect the link to the home screen.
In your App.js, get isAuthenticated value using connect() so it will re-render with latest value of isAuthencticated after login and your will see the updated urls

Categories

Resources