I am aiming to display the component "SignIn" when I select the sign in button in the landing page. However, the component in the landing page is still displayed after selecting the button. Here are some images illustrating this problem.
Before Click: enter image description here
After Click: enter image description here
The issue is the second image. What could be the biggest cause of it?
Input is greatly appreciated.
Code - Home Page (LandingPage):
import React from 'react';
import Button from 'react-bootstrap/Button';
import Form from 'react-bootstrap/Form';
import { Link } from 'react-router-dom';
import * as ROUTES from '../../routes.jsx';
import './LandingPage.css'
export default class LandingPage extends React.Component {
render() {
return(
<div>
<Button className="signInButton" variant="light"><Link to={ROUTES.SIGN_IN}>Sign In</Link></Button>
<h1 className="landingBanner" >Streamosphere</h1>
<SignUpFormBase/>
</div>
);
}
}
const INITIAL_STATE = {
email: '',
password: '',
error: null,
};
export default class SignUpFormBase extends React.Component {
constructor(props) {
super(props);
this.state = { ...INITIAL_STATE };
}
onSubmit = event => {
console.log("Props");
console.log(this.props);
const { history } = this.props;
const { email, password } = this.state;
this.props.firebase
.doCreateUserWithEmailAndPassword(email, password)
.then(authUser => {
this.setState({ ...INITIAL_STATE });
})
.catch(error => {
this.setState({ error });
});
event.preventDefault();
};
onChange = event => {
this.setState({ [event.target.name]: event.target.value });
};
render() {
const {
email,
password,
error,
} = this.state;
const isInvalid = password === '' || email === '';
return (
<Form className="signUpForm"
onSubmit={this.onSubmit}>
<h1 className="signUpBanner">Sign Up </h1>
<Form.Group controlId="formSignUpEmail">
<Form.Label>Email address</Form.Label>
<Form.Control name="email"
value={email}
onChange={this.onChange}
type="email"
placeholder="Enter email" />
<Form.Text className="text-muted">
We'll never share your email with anyone else.
</Form.Text>
</Form.Group>
<Form.Group controlId="formSignUpPassword">
<Form.Label>Password</Form.Label>
<Form.Control name="password"
value={password}
onChange={this.onChange}
type="password"
placeholder="Password" />
</Form.Group>
<Button type="submit"
disabled={isInvalid}
className="signUpButton"
variant="light" >
Sign Up
</Button>
{error && <p>{error.message}</p>}
</Form>
);
}
}
const SignUpLink = () => (
<p>
Already have an account? <Link to={ROUTES.SIGN_IN}>Sign In</Link>
</p>
);
Sign In (file w/ SignIn Component):
import React, { Component } from 'react';
import SignUpLink from './LandingPage.jsx'
import * as ROUTES from '../../routes.jsx';
import Form from 'react-bootstrap/Form';
import Button from 'react-bootstrap/Button';
import './LandingPage.css'
export default class SignInPage extends Component {
render() {
return(
<div>
<h1 className="landingBanner" >Streamosphere</h1>
<SignInFormBase/>
<SignUpLink />
</div>
);
}
}
const INITIAL_STATE = {
email: '',
password: '',
error: null,
};
export default class SignInFormBase extends Component {
constructor(props) {
super(props);
this.state = { ...INITIAL_STATE };
}
onSubmit = event => {
const { email, password } = this.state;
this.props.firebase
.doSignInWithEmailAndPassword(email, password)
.then(() => {
this.setState({ ...INITIAL_STATE });
this.props.history.push(ROUTES.HOME);
})
.catch(error => {
this.setState({ error });
});
event.preventDefault();
};
onChange = event => {
this.setState({ [event.target.name]: event.target.value });
};
render() {
const { email, password, error } = this.state;
const isInvalid = password === '' || email === '';
return (
<Form className="signUpForm"
onSubmit={this.onSubmit}>
<h1 className="signUpBanner"> Sign In </h1>
<Form.Group controlId="formSignInEmail">
<Form.Label>Email address</Form.Label>
<Form.Control name="email"
value={email}
onChange={this.onChange}
type="email"
placeholder="Enter email" />
<Form.Text className="text-muted">
We'll never share your email with anyone else.
</Form.Text>
</Form.Group>
<Form.Group controlId="formSignInPassword">
<Form.Label>Password</Form.Label>
<Form.Control name="password"
value={password}
onChange={this.onChange}
type="password"
placeholder="Password" />
</Form.Group>
<Button type="submit"
disabled={isInvalid}
className="signUpButton"
variant="light" >
Sign In
</Button>
{error && <p>{error.message}</p>}
</Form>
);
}
}
URL Routes (routes.jsx):
export const LANDING = '/';
export const SIGN_IN = '/signin';
export const HOME = '/home';
export const ACCOUNT = '/account';
App.jsx (entry point, where LandingPage is the 1st page rendered):
import { Route } from 'react-router'
import React from 'react';
import LandingPage from './components/containers/LandingPage'
import SignInPage from './components/containers/SignIn'
import HomePage from './components/containers/HomePage'
import * as ROUTES from './routes.jsx';
class App extends React.Component {
render() {
return (
<div>
<Route exact path={ROUTES.LANDING} component={LandingPage} />
<Route path={ROUTES.HOME} component={HomePage} />
<Route path={ROUTES.SIGN_IN} component={SignInPage} />
</div>
);
}
}
export default App;
It is because of the Link from react-router-dom.
You could circumvent it by reloading the whole page.
For example, use <a href="/sign-in></a> instead.
You need to wrap all routes in App with Switch which would render only one matching child component.
// App.jsx
import { Route, Switch } from 'react-router'
import React from 'react';
import LandingPage from './components/containers/LandingPage'
import SignInPage from './components/containers/SignIn'
import HomePage from './components/containers/HomePage'
import * as ROUTES from './routes.jsx';
class App extends React.Component {
render() {
return (
<Switch>
<Route exact path={ROUTES.LANDING} component={LandingPage} />
<Route path={ROUTES.HOME} component={HomePage} />
<Route path={ROUTES.SIGN_IN} component={SignInPage} />
</Switch>
);
}
}
export default App;
Related
i have a problem when i login using username and password. and when i submit. the page still not changes to /admin/index. but the path link already go to admin/index . for the example http://localhost:3000/ is the login page when i try to login the browser path become http://localhost:3000/admin/index but the page still not changes yet . and i must refresh the page first so the page will changes to dashboard
index.js
import React from "react";
import { createStore } from 'redux'
import { Provider } from 'react-redux'
import { Router, Route, Switch} from "react-router-dom";
import { createBrowserHistory } from 'history';
import "assets/vendor/nucleo/css/nucleo.css";
import "assets/vendor/#fortawesome/fontawesome-free/css/all.min.css";
import "assets/scss/argon-dashboard-react.scss";
import AdminLayout from "layouts/Admin.js";
import reducer from './actions/reducer'
import LandingLogin from './layouts/LandingLogin.js'
import LandingRegister from './layouts/LandingRegister.js'
const store = createStore(reducer);
const customHistory = createBrowserHistory();
class App extends React.Component {
render () {
return (
<Provider store = {store}>
<Router history={customHistory}>
<Switch>
<Route path="/admin" render={props => <AdminLayout {...props} />} />
<Route path="/" render= {() => <LandingLogin/>} />
<Route exact path="/register" render= {() => <LandingRegister/>} />
</Switch>
</Router>
</Provider>
)
}
}
export default App;
login.js
import React, { Fragment } from 'react'
import { connect } from 'react-redux'
import axios from 'axios';
import { createBrowserHistory } from 'history';
import { Link } from 'react-router-dom'
// reactstrap components
import {
Button,
Card,
CardBody,
FormGroup,
Form,
Input,
InputGroupAddon,
InputGroupText,
InputGroup,
Col
} from "reactstrap";
const customHistory = createBrowserHistory();
class Login extends React.Component {
constructor(props) {
super(props);
const token = localStorage.getItem("token");
let isLogedIn = true
if (token === null) {
isLogedIn = false
}
this.state = {
post : [],
isLogedIn,
id : '',
email : '',
password: '',
}
this.handleForm = this.handleForm.bind(this);
this.submitLogin = this.submitLogin.bind(this);
}
getPostAPI = () => {
axios.get('http://localhost:8001/datauser')
.then((res) => {
this.setState ({
post : res.data
})
})
}
getPostAPI2 = () => {
axios.get('http://localhost:8001/dataadmin')
.then((res) => {
this.setState ({
post : res.data
})
})
}
handleForm = (e) => {
this.setState ({
[e.target.name] : e.target.value
})
}
submitLogin = (event) => {
event.preventDefault();
const { post, email, password } = this.state;
if(post.find(event => `${event.email}${event.password}` === `${email}${password}` )) {
localStorage.setItem("token","123456781234")
localStorage.setItem("username",email);
localStorage.setItem("password",password);
this.setState ({
isLogedIn : true
})
} else {
alert("Email atau Password Salah!");
this.setState ({
email : '',
password: ''
})
}
}
componentDidMount () {
this.getPostAPI2();
}
render() {
const { email, password } = this.state
if (this.state.isLogedIn) {
customHistory.push('/admin/index');
}
return (
<Fragment>
<Col lg="5" md="7">
<Card className="bg-secondary shadow border-0">
<CardBody className="px-lg-5 py-lg-5">
<div className="text-center text-muted mb-4">
<h2>Form Login</h2>
</div>
<Form role="form" onSubmit = {this.submitLogin}>
<FormGroup className="mb-3">
<InputGroup className="input-group-alternative">
<InputGroupAddon addonType="prepend">
<InputGroupText>
<i className="ni ni-email-83" />
</InputGroupText>
</InputGroupAddon>
<Input onChange={this.handleForm} value={email} name = "email" placeholder="Email" type="email" required />
</InputGroup>
</FormGroup>
<FormGroup>
<InputGroup className="input-group-alternative">
<InputGroupAddon addonType="prepend">
<InputGroupText>
<i className="ni ni-lock-circle-open" />
</InputGroupText>
</InputGroupAddon>
<Input onChange={this.handleForm} value={password} name = "password" placeholder="Password" type="password" required/>
</InputGroup>
</FormGroup>
<div className="custom-control custom-control-alternative custom-checkbox">
<input
className="custom-control-input"
id=" customCheckLogin"
type="checkbox"
/>
<label
className="custom-control-label"
htmlFor=" customCheckLogin"
>
<span className="text-muted">Remember me</span>
</label>
</div>
<div className="text-center">
<Button className="my-4" color="primary" type="submit">
Log in
</Button>
</div>
</Form>
</CardBody>
</Card>
</Col>
</Fragment>
);
}
}
function select(state) {
return {
users: state.users
}
}
export default connect(select)(Login);
i expect when login, the page directly change to dashboard without refresh the page. please tell me something what should i do
This question seems like duplicate but it's not. I understand the error and have solved such error number of time but this time I couldn't figure out what's causing infinite loop.
here is code for react component causing the error:
import React, { Component } from 'react';
import { Redirect } from 'react-router-dom';
import PropTypes from 'prop-types';
import './Login.scss';
import axios from 'axios';
import { endPoint } from '../App/path';
import { logIn, isLoggedIn } from '../App/TokenStore';
const re = /^[a-zA-Z0-9_-]{3,15}$/;
class Login extends Component {
constructor() {
super();
this.state = {
username: '',
password: '',
errorMessage: 'Please Login to proceed!',
};
}
onUserNameChange = (e) => {
this.setState({ username: e.target.value });
}
onPasswordChange = (e) => {
this.setState({ password: e.target.value });
}
onFormSubmit = (event) => {
event.preventDefault();
const { username, password } = this.state;
const { history } = this.props;
const isUserNameValid = re.test(String(username).toLowerCase());
if (isUserNameValid) {
axios.post(`${endPoint}/login.json`, { username, password })
.then((response) => {
if (response.status === 200) {
if (response.statusText === 'OK') {
this.setState({
username: '', password: '', errorMessage: '',
});
if (response.config.data) {
console.log(response);
logIn(response.config.data, 'response.config.data.password');
history.push('/dashboard');
} else {
throw new Error();
}
} else {
this.setState({ errorMessage: 'Please enter valid credential!' });
}
}
}).catch((err) => {
if (err.response) {
this.setState({ errorMessage: 'Please enter valid username!' });
} else {
this.setState({ errorMessage: 'Unknown Error!!' });
}
});
} else {
this.setState({ errorMessage: 'Please enter valid username!' });
}
}
render() {
if (isLoggedIn()) {
return <Redirect to="/dashboard" />;
}
const {
username, password, errorMessage,
} = this.state;
return (
<div className="Login">
<form className="Form" onSubmit={this.onFormSubmit}>
<p className="errorMessage">{errorMessage}</p>
<div className="form__group">
<label id="username" className="Label" htmlFor="username">
<i className="fa fa-user" />
<b>Username</b>
</label>
<input
value={username}
onChange={e => this.onUserNameChange(e)}
id="username"
type="username"
placeholder="Your username"
required
/>
</div>
<div className="form__group">
<label id="password" className="Label" htmlFor="password">
<i className="fa fa-key" />
<b>Password</b>
</label>
<input
value={password}
onChange={e => this.onPasswordChange(e)}
id="password"
type="password"
placeholder="Your Password"
required
/>
</div>
<button type="submit" className="Btn">LOGIN</button>
</form>
</div>
);
}
}
Login.propTypes = {
history: PropTypes.shape(),
};
Login.defaultProps = { history: {} };
export default Login;
these are the other function I am using in the above component:
export const logIn = (username, token) => {
sessionStorage.setItem('username', username);
sessionStorage.setItem('loggedIn', true);
sessionStorage.setItem('token', token);
};
export const isLoggedIn = () => Boolean(sessionStorage.getItem('loggedIn'));
here is dashboard component
import React from 'react';
import { NavLink } from 'react-router-dom';
import './Dashboard.scss';
const dashboard = () => (
<div className="container">
<div className="row">
<div className="card col-5 mr-auto ml-auto">
<h5 className="card-header">Lorem ipsum</h5>
<div className="card-body">
<h5 className="card-title">Lorem ipsum</h5>
<p className="card-text">Lorem ipsum</p>
<NavLink to="/dashboard/VRlist" className="btn btn-dashboard">Update/Delete</NavLink>
</div>
</div>
<div className="card col-5 mr-auto ml-auto">
<h5 className="card-header">Lorem ipsum</h5>
<div className="card-body">
<h5 className="card-title">Lorem ipsum</h5>
<p className="card-text">Lorem ipsum</p>
<NavLink to="/dashboard/registration" className="btn btn-dashboard"> Registration</NavLink>
</div>
</div>
</div>
</div>
);
export default dashboard;
here is my main app component
import React from 'react';
import { Switch, Route } from 'react-router-dom';
import Navbar from './Navbar/Navbar';
import Login from './Login/Login';
import Dashboard from './Dashboard/Dashboard';
import { isLoggedIn } from './App/TokenStore';
import VRlist from './VRlist/VRlist';
import NewRegistration from './newRegistration/newRegistration';
import UpdateRegistration from './updateRegistration/updateRegistration';
const App = () => {
if (!isLoggedIn()) {
return (
<div>
<Navbar />
<Route component={Login} />
</div>
);
}
return (
<div>
<Navbar />
<Switch>
<Route exact path="/" component={Login} />
<Route path="/dashboard/VRlist/edit/:id" component={UpdateRegistration} />
<Route path="/dashboard/VRlist" component={VRlist} />
<Route path="/dashboard/registration" component={NewRegistration} />
<Route path="/dashboard" component={Dashboard} />
<Route component={Login} />
</Switch>
</div>
);
};
export default App;
Now when I run the application and do login, this error will happen only for the first time login in the current tab, if I refresh the page the error will go away.
Apparently, I've used react-router and react-router-dom version 5, that's what was causing an infinite render loop while calling an history.push(), however for the rest of the components 'history.push()' was working fine but login page. Though switching over to version 4.3.1 emitted issue completely.
I am trying to redirect a user after login to home page, the redirect happens (this I know because the url changes and I go to a new page), but the content of the page doesn't load. I keep on getting this error
Warning: You tried to redirect to the same route you're currently on: "/index"
Here's my code for Login.js:
import React, { Component } from 'react';
import '../App.css';
import 'whatwg-fetch';
import { connect } from 'react-redux';
import { loginUser } from './../store/actions/loginActions';
import { Redirect, withRouter } from 'react-router-dom';
class Login extends Component {
constructor(props) {
super(props);
this.state = {
Email: '', Password: '', isloggedin: false
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({ [event.target.name]: event.target.value });
}
handleSubmit(event) {
event.preventDefault();
this.props.loginUser(this.state)
}
render() {
const { authError, token } = this.props;
if(token) return <Redirect to="/index" /> // I'm telling it to redirect if the state has a token
return (
<div className="Background">
<Card
title="Login"
style={{ width: 400 }}
>
<Form onSubmit={this.handleSubmit} className="login-form">
<Form.Item>
<Input prefix={<Icon type="user" style={{ color: 'rgba(0,0,0,.25)' }} />} name="Email" type="text" onChange={this.handleChange} />
</Form.Item>
<Form.Item>
<Input prefix={<Icon type="lock" style={{ color: 'rgba(0,0,0,.25)' }} />} type="password" name="Password" onChange={this.handleChange} />
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit" disable='notloggedin' className="login-form-button">
Log in
</Button>
</Form.Item>
</Form>
<div>
{ authError ? <p> { authError } </p> : null }
</div>
</Card>
</div>
);
}
}
const mapStateToProps = (state) => {
return {
authError: state.auth.authError,
token: state.auth.token
}
}
const mapDispatchToProps = (dispatch) => {
return {
loginUser: (data) => dispatch(loginUser(data))
}
}
export default withRouter(connect(mapStateToProps, mapDispatchToProps) (Login));
My action is:
export const loginUser = (data) => {
return (dispatch, getState) => {
fetch(url, {
credentials: 'include',
method: 'POST',
headers: headers,
body: JSON.stringify(data)})
.then(res => { if (res.ok) {
return res.json() }
else {
return Promise.reject({
status: res.status,
statusText: res.statusText
})
}
})
.then(function(response) {
dispatch({type: 'LOGIN_USER', value: response.AccessToken });
})
.catch((err) => {
dispatch({type: 'LOGIN_USER_FAILED', err });
})
}
};
and my App.js is
import React, { Component } from 'react';
import { BrowserRouter, Switch, Route } from 'react-router-dom';
import './App.css';
import Login from './components/Login';
import Home from './components/Home';
class App extends Component {
render() {
return (
<div className="App">
<header className="App-header">
<h3 className="App-logo"> App Load </h3>
</header>
<BrowserRouter>
<Switch>
<Route path="/" component={Login} />
<Route path="/index" component={Home} />
</Switch>
</BrowserRouter>
);}}
export default App;
Could anyone please let me know if they see any reason as to why the redirect is working but not loading the page components? I'll really appreciate any pointers.
try to wrap you whole App component into BrowserRouter
I shifted this <Route path="/" component={Login} /> to the bottom of my routes in App.js and it worked.
I am trying to build a simple react login app that navigates to a home page after logging in using this.props.history.push(). Unfortunately, in all of my components this.props is undefined. Here are the relevant portions:
Root:
import React from 'react'
import {
BrowserRouter as Router,
Route
} from 'react-router-dom'
import Login from './views/Login'
import Index from './views/Index'
import Home from './views/Home'
const App = () => {
return(
<Router>
<div>
<Route exact path="/" component={Index}/>
<Route path="/login" component={Login}/>
<Route path="/home" component={Home}/>
</div>
</Router>
)
}
export default App
Index:
import React from 'react'
import Login from './Login'
import Home from './Home'
const Index = () => {
if (localStorage.getItem("username")) {
return(
<Home/>
);
} else {
return (
<Login/>
)
}
}
export default Index
Login:
import React from 'react'
const Login = () => {
let user, pass
const login = e => {
e.preventDefault();
fetch("http://localhost:3000/api/login", {
method: "GET",
headers: {
"user": user.value,
"pass": pass.value
}
})
.then(response => response.json())
.then(function(data) {
if (data.user) {
localStorage.setItem("username", data.user)
this.props.history.push("/");
} else {
console.log("Failed to get user")
}
})
}
return(
<div>
<h1>Login</h1>
<form onSubmit={login}>
<label> Username:
<input type="text" className="form-control col-md-12" ref = {node => user = node}/>
</label>
<label> Password:
<input type="password" className="form-control col-md-12" ref = {node => pass = node}/>
</label>
<br />
<input type="submit" value="Submit" />
</form>
</div>
)
}
export default Login
You also need withRouter from react-router-dom. Your login should look like this:
import React from 'react'
import { withRouter } from 'react-router-dom'
const Login = (props) => {
let user, pass
const login = e => {
e.preventDefault();
fetch("http://localhost:3000/api/login", {
method: "GET",
headers: {
"user": user.value,
"pass": pass.value
}
})
.then(response => response.json())
.then(function(data) {
if (data.user) {
localStorage.setItem("username", data.user)
props.history.push("/");
} else {
console.log("Failed to get user")
}
})
}
return(
<div>
<h1>Login</h1>
<form onSubmit={login}>
<label> Username:
<input type="text" className="form-control col-md-12" ref = {node => user = node}/>
</label>
<label> Password:
<input type="password" className="form-control col-md-12" ref = {node => pass = node}/>
</label>
<br />
<input type="submit" value="Submit" />
</form>
</div>
)
}
export default withRouter(Login)
withRouter is a higher order component. Higher order components are like wrappers that add additional functionality. They take a component as an argument and return a new component; in this case withRouter adds the history props.
Can read more about HOCs here: https://reactjs.org/docs/higher-order-components.html
I've subcomponent named homeMessage which contains the form and with one input tag.
import React,{Component} from "react";
import {BrowserRouter as Router, Link, Switch, Route} from "react-router-dom";
import SignUp from './SignUp';
class App extends Component {
constructor(props){
super(props);
this.state = {
firstName: ''
};
}
inputData = (event) =>
{
this.setState({
[event.target.name]:event.target.value
});
}
submitData = (event) =>
{
event.preventDefault();
}
render(){
let homeMessage = () =>
{
return(
<div>
<form onSubmit={this.submitData}>
FirstName:
<input type="text" name="firstName" onChange={this.inputData}/>
<button type="submit">Submit</button>
</form>
<Link to="/src/SignUp">SignUp</Link>
</div>
);
}
return(
<Router>
<div>
<Route exact path="/" component={homeMessage}/>
<Route path="/src/SignUp" render={(props)=><SignUp firstName={this.state.firstName}/>}/>
</div>
</Router>
);
}
}
export default App;
When I write content of homeMessage contents in original return method it works fine but when I create custom return component like above on every keystroke it removes my cursor!
Change the homeMessage sub component's definition to this -
const homeMessage = (
<div>
<form onSubmit={this.submitData}>
FirstName:
<input type="text" name="firstName" onChange={this.inputData}/>
<button type="submit">Submit</button>
</form>
<Link to="/src/SignUp">SignUp</Link>
</div>
);
This should work fine.