I have a login page, after successfull login, i want to move to dashboard, where i want to pass the mail id of logged in user to dashboard, i tried passing it by using states but it is not working
from login,
if (this.Auth.getToken()) {
this.props.history.replace({
pathname: '/dashboard',
state: { email: this.state.email }
})
}
to dashboard,
componentDidMount() {
if (this.Auth.loggedIn()){
console.log(this.props.location.state.email)
}else {
this.props.history.replace('/login');
}
}
error,
TypeError: Cannot read property 'email' of undefined
Dashboard.componentDidMount
src/components/auth/Dashboard.js:15
12 | }
13 | componentDidMount() {
14 | if (this.Auth.loggedIn()){
> 15 | console.log(this.props.location.state.email)
16 | }else {
17 | this.props.history.replace('/login');
18 | }
full code of login:
import React, { Component } from 'react'
// import * as service from '../../services/service';
import AuthService from '../../services/AuthService'
class Login extends Component {
constructor() {
super()
this.state = {
email: '',
password: ''
}
this.Auth = new AuthService();
this.onChange = this.onChange.bind(this);
this.onSubmit = this.onSubmit.bind(this);
}
componentWillMount() {
if (this.Auth.loggedIn())
this.props.history.replace('/dashboard');
}
onChange(e) {
this.setState({ [e.target.name]: e.target.value })
}
onSubmit(e) {
e.preventDefault();
var user = {
email: this.state.email,
password: this.state.password
}
var form1 = document.getElementById("login");
if (form1.checkValidity() === true) {
this.Auth.login(user)
.then(res => {
if (this.Auth.getToken()) {
this.props.history.replace({
pathname: '/dashboard',
state: { email: this.state.email }
})
}
if (res.status === '404') {
document.getElementById('error').style.color = 'red';
document.getElementById('error').innerHTML = 'Mail Id or Password is Incorrect';
}
})
.catch(err => {
console.log(err);
})
}
}
render() {
return (
<div>
<div className="login">
<div className="container">
<div className="row">
<div className="col-md-8 m-auto">
<h1 className="display-4 text-center">Log In</h1>
<p className="lead text-center">Sign in to your account</p>
<form id="login" onSubmit={this.onSubmit} noValidate>
<span className="lead text-center" id='error'></span>
<div className="form-group">
<input type="email" className="form-control form-control-lg" placeholder="Email Address" name="email" onChange={this.onChange} required />
<div className="invalid-feedback">Enter valid email</div>
</div>
<div className="form-group">
<input type="password" className="form-control form-control-lg" placeholder="Password" name="password" minLength="5" onChange={this.onChange} required />
<div className="invalid-feedback">Enter atleast 5 characters.</div>
</div>
<input type="submit" className="btn btn-info btn-block mt-4" />
</form>
</div>
</div>
</div>
</div>
</div>
)
}
}
export default Login;
full code of dashboard,
import React, { Component } from 'react'
import { Link } from 'react-router-dom';
// import * as service from '../../services/service';
import AuthService from '../../services/AuthService'
class Dashboard extends Component {
constructor() {
super()
this.state = {
}
this.Auth = new AuthService();
}
componentDidMount() {
if (this.Auth.loggedIn()){
console.log(this.props.location.state.email)
}else {
this.props.history.replace('/login');
}
}
render() {
return (
<div>
<div className="dashboard">
<div className="container">
<div className="row">
<div className="col-md-8 m-auto">
<h1 className="display-4 text-center">Dashboard</h1>
</div>
</div>
</div>
</div>
</div>
)
}
}
export default Dashboard;
App.js
import React, { Component } from 'react';
import { Route, BrowserRouter as Router } from 'react-router-dom';
import './App.css';
import Navbar from './components/layout/Navbar'
import Footer from './components/layout/Footer'
import Landing from './components/layout/Landing'
import Login from './components/auth/Login'
import Dashboard from './components/auth/Dashboard'
import Register from './components/auth/Register'
import Logout from './components/auth/Logout'
import Profile from './components/auth/Profile'
class App extends Component {
render() {
return (
<Router>
<div className="App">
<Navbar />
<Route exact path="/" component={Landing} />
<div className="container">
<Route exact path="/login" component={Login} />
<Route exact path="/register" component={Register} />
<Route exact path="/dashboard" component={Dashboard} />
<Route exact path="/logout" component={Logout} />
<Route exact path="/profile" component={Profile} />
</div>
<Footer />
</div>
</Router>
);
}
}
export default App;
Update react-router version to ^4.0.0
Related
I am trying to implement this feature in my React JS app where if I login successfully, the UI would display the Logout button in the navbar. But if I click on the Logout, I would be logged out from the main UI and redirected to the Login Page where the navbar won't have any Logout Button. Currently, when I log in to the main UI successfully, then I have to refresh the browser tab to show the logout button. It does not appear automatically once I log in successfully.
This is my header Component:
import React, { Component } from "react";
import { BrowserRouter as Router, Link } from "react-router-dom";
import AuthenticationService from "../Login/AuthenticationService";
class HeaderComponent extends Component {
render() {
const isUserLoggedIn = sessionStorage.getItem("authenticatedUser");
console.log(isUserLoggedIn);
return (
<nav className="navbar navbar-expand-lg ">
<Router>
<div className="container-fluid">
<a className="navbar-brand" href="#">
<span className="header-title">TODO APP</span>
</a>
<ul className="navbar-nav d-flex flex-row ms-auto me-3">
{isUserLoggedIn && (
<Link
to="/login"
onClick={() => {
window.location.href = "/login";
}}
>
{" "}
<button
className="btn btn-success logout-button"
onClick={AuthenticationService.logout}
>
Logout
</button>
</Link>
)}
</ul>
</div>
</Router>
{" "}
</nav>
);
}
}
export default HeaderComponent;
The isUserLoggedIn is a boolean value that is retrieved from the session storage. If isUserLoggedIn is true then the Logout button would be displayed on the Navbar.
const isUserLoggedIn = sessionStorage.getItem("authenticatedUser");
The AuthenticationService.js file is:
import React, { Component } from "react";
class AuthenticationService extends Component {
registerSuccessfulLogin(username, password) {
console.log("Login Successful");
sessionStorage.setItem("authenticatedUser", username);
console.log(sessionStorage.getItem("authenticatedUser"));
}
isUserLoggedIn() {
let user = sessionStorage.getItem("authenticatedUser");
if (user === null) {
return false;
} else {
return true;
}
// return true;
}
logout() {
sessionStorage.removeItem("authenticatedUser");
}
getLoggedInUserName() {
let user = sessionStorage.getItem("authenticatedUser");
if (user === null) return "";
return user;
}
}
export default new AuthenticationService();
The App.js component is:
import "./App.css";
import DropDownMenu from "./components/DropdownMenu/DropDownMenu";
import HeaderComponent from "./components/Header/HeaderComponent";
import LoginComponent from "./components/Login/LoginComponent";
import {
BrowserRouter as Router,
Routes,
Route,
useParams,
Link,
} from "react-router-dom";
import "./styles.css";
import "./loginStyle.css";
import "./Header.css";
import ErrorComponent from "./components/search-options/ErrorComponent";
import AuthenticatedRoute from "./components/DropdownMenu/AuthenticatedRoute";
function App() {
return (
<div className="App">
<HeaderComponent />
<Router>
<Routes>
<Route path="/" element={<LoginComponent />}></Route>
{/* <Route path="/login" element={<Navigate to="/LoginComponent" />} /> */}
<Route path="/login" default element={<LoginComponent />}></Route>
<Route
path="/pst"
element={
<AuthenticatedRoute>
<DropDownMenu />
</AuthenticatedRoute>
}
></Route>
<Route path="*" element={<ErrorComponent />}></Route>
</Routes>
</Router>
</div>
);
}
export default App;
I am not sure why do I have to refresh the Tab to show the Logout button on to the NavBar.
EDIT
I have added the Login component for further reference:
import axios from "axios";
import { data } from "jquery";
import React, { Component } from "react";
import { useNavigate } from "react-router";
import App from "../../App";
import HeaderComponent from "../Header/HeaderComponent";
import GetUserIp from "../tracking/GetUserIp";
import TrackLoginActivity from "../tracking/TrackLoginActivity";
import AuthenticationService from "./AuthenticationService";
class LoginComponent extends Component {
constructor(props) {
super(props);
this.state = {
username: "",
password: "",
ipAddress: "",
hasLoginFailed: false,
isUserLoggedIn: false,
};
this.handleCredentialChange = this.handleCredentialChange.bind(this);
this.submitLogin = this.submitLogin.bind(this);
}
handleCredentialChange(event) {
console.log(event.target.name);
this.setState({ [event.target.name]: event.target.value });
}
submitLogin(event) {
event.preventDefault();
var session_url =
"login check api url";
GetUserIp.retrieveIpAddress().then((response) => {
this.setState({ ipAddress: response.data.ip });
});
console.log(this.state.ipAddress);
axios
.post(
session_url,
{},
{
auth: {
username: this.state.username,
password: this.state.password,
},
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
}
)
.then((response) => {
console.log("Authenticated");
console.log(this.props);
AuthenticationService.registerSuccessfulLogin(
this.state.username,
this.state.password
);
this.props.navigate(`/pst`);
//track user login activity into the DB Entity, smart_tool_login_logs
TrackLoginActivity.trackSuccessfulLogin(
this.state.username,
this.state.ipAddress
);
})
.catch((error) => {
console.log("Error on autheication");
this.setState({ hasLoginFailed: true });
});
}
render() {
return (
<div className="login-app">
<form action="" className="login-form" onSubmit={this.submitLogin}>
<div className="container">
<input
type="text"
placeholder="username"
name="username"
className="username-value"
maxLength={30}
autoComplete="on"
value={this.state.username}
onChange={this.handleCredentialChange}
/>
<input
type="password"
placeholder="password"
name="password"
className="password-value"
maxLength={30}
autoComplete="on"
value={this.state.password}
onChange={this.handleCredentialChange}
/>
{this.state.hasLoginFailed && (
<div className="login-fail-message">
Invalid username/password
</div>
)}
<div className="login-btn"></div>
<button className="btn btn-success login-btn" type="submit">
Login
</button>
</div>
</form>
</div>
);
}
}
function WithNavigate(props) {
let navigate = useNavigate();
return <LoginComponent {...props} navigate={navigate} />;
}
export default WithNavigate;
Your header component is a stateless component, it has neither props nor internal state, so it is only rendered once with the initial value of isUserLoggedIn.
If you want the header component to react to the login status, it needs to be notified in some way that the value has changed. The easiest way to do so is to store this information in the state of your App component, then passing it down as a prop to the HeaderComponent.
// App.js
import "./App.css";
import DropDownMenu from "./components/DropdownMenu/DropDownMenu";
import HeaderComponent from "./components/Header/HeaderComponent";
import LoginComponent from "./components/Login/LoginComponent";
import {
BrowserRouter as Router,
Routes,
Route,
useParams,
Link,
} from "react-router-dom";
import "./styles.css";
import "./loginStyle.css";
import "./Header.css";
import ErrorComponent from "./components/search-options/ErrorComponent";
import AuthenticatedRoute from "./components/DropdownMenu/AuthenticatedRoute";
import AuthenticationService from "../Login/AuthenticationService";
function App() {
const [isUserLoggedIn, setIsUserLoggedIn] = useState(AuthenticationService.isUserLoggedIn()) // use the session storage to get the initial state's value
function onLoginSuccessful() {
setIsUserLoggedIn(true); // update the state to notify React the value has changed
}
return (
<div className="App">
<HeaderComponent isUserLoggedIn={isUserLoggedIn} /> {/* pass down the state value as a prop */}
<Router>
<Routes>
<Route path="/" element={<LoginComponent onLoginSuccessful={onLoginSuccessful}/>}></Route>
{/* <Route path="/login" element={<Navigate to="/LoginComponent" />} /> */}
<Route path="/login" default element={<LoginComponent onLoginSuccessful={onLoginSuccessful} />}></Route>
<Route
path="/pst"
element={
<AuthenticatedRoute>
<DropDownMenu />
</AuthenticatedRoute>
}
></Route>
<Route path="*" element={<ErrorComponent />}></Route>
</Routes>
</Router>
</div>
);
}
export default App;
// HeaderComponent.js
import React, { Component } from "react";
import { BrowserRouter as Router, Link } from "react-router-dom";
import AuthenticationService from "../Login/AuthenticationService";
class HeaderComponent extends Component {
render() {
const isUserLoggedIn = this.props.isUserLoggedIn; // retrieve the value from the props
console.log(isUserLoggedIn);
return (
<nav className="navbar navbar-expand-lg ">
<Router>
<div className="container-fluid">
<a className="navbar-brand" href="#">
<span className="header-title">TODO APP</span>
</a>
<ul className="navbar-nav d-flex flex-row ms-auto me-3">
{isUserLoggedIn && (
<Link
to="/login"
onClick={() => {
window.location.href = "/login";
}}
>
{" "}
<button
className="btn btn-success logout-button"
onClick={AuthenticationService.logout}
>
Logout
</button>
</Link>
)}
</ul>
</div>
</Router>
{" "}
</nav>
);
}
}
export default HeaderComponent;
Note that you also have to pass a callback to LoginComponent to be called once the user successfully logs in. Using state updates, React gets notified that the value of isUserLoggedIn has changed and will re-render the components that depend on this value, including HeaderComponent.
EDIT: I updated the implementation of LoginComponent with the callback I mentionned
// LoginComponent.js
import axios from "axios";
import { data } from "jquery";
import React, { Component } from "react";
import { useNavigate } from "react-router";
import App from "../../App";
import HeaderComponent from "../Header/HeaderComponent";
import GetUserIp from "../tracking/GetUserIp";
import TrackLoginActivity from "../tracking/TrackLoginActivity";
import AuthenticationService from "./AuthenticationService";
class LoginComponent extends Component {
constructor(props) {
super(props);
this.state = {
username: "",
password: "",
ipAddress: "",
hasLoginFailed: false,
isUserLoggedIn: false,
};
this.handleCredentialChange = this.handleCredentialChange.bind(this);
this.submitLogin = this.submitLogin.bind(this);
}
handleCredentialChange(event) {
console.log(event.target.name);
this.setState({ [event.target.name]: event.target.value });
}
submitLogin(event) {
event.preventDefault();
var session_url =
"login check api url";
GetUserIp.retrieveIpAddress().then((response) => {
this.setState({ ipAddress: response.data.ip });
});
console.log(this.state.ipAddress);
axios
.post(
session_url,
{},
{
auth: {
username: this.state.username,
password: this.state.password,
},
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
}
)
.then((response) => {
console.log("Authenticated");
console.log(this.props);
AuthenticationService.registerSuccessfulLogin(
this.state.username,
this.state.password
);
// add this line to your `LoginComponent` so that
// onLoginSuccessul is called when user is logged in
this.props.onLoginSuccessful();
this.props.navigate(`/pst`);
//track user login activity into the DB Entity, smart_tool_login_logs
TrackLoginActivity.trackSuccessfulLogin(
this.state.username,
this.state.ipAddress
);
})
.catch((error) => {
console.log("Error on autheication");
this.setState({ hasLoginFailed: true });
});
}
render() {
return (
<div className="login-app">
<form action="" className="login-form" onSubmit={this.submitLogin}>
<div className="container">
<input
type="text"
placeholder="username"
name="username"
className="username-value"
maxLength={30}
autoComplete="on"
value={this.state.username}
onChange={this.handleCredentialChange}
/>
<input
type="password"
placeholder="password"
name="password"
className="password-value"
maxLength={30}
autoComplete="on"
value={this.state.password}
onChange={this.handleCredentialChange}
/>
{this.state.hasLoginFailed && (
<div className="login-fail-message">
Invalid username/password
</div>
)}
<div className="login-btn"></div>
<button className="btn btn-success login-btn" type="submit">
Login
</button>
</div>
</form>
</div>
);
}
}
function WithNavigate(props) {
let navigate = useNavigate();
return <LoginComponent {...props} navigate={navigate} />;
}
export default WithNavigate;
I believe the issue is the isAuthenticated state in the parent APP component is not being changed when bcrypt has confirmed credentials in the child Login component. I can't seem to get it to change.
I have added some console.log to see if change takes place and console.log 2 is skipped over and is never read.
The examples I keep finding pass a value back to parent when it the return() "html" portion of the child component function. I tried to use that as a basis for passing a call to the funciton in the parent to change the state. As I am here that method does not seem to work. Any guidance and/or explanation would be greatly appreciated.
The ideal situation would be after being authenticated by bcrypt, user would be redirected to private route /Post
APP:
import React, {useState} from 'react';
import './App.css';
import Nav from "./Nav";
import About from './About';
import Creater from './Creater';
import {BrowserRouter as Router, Switch, Route, Redirect, Link } from 'react-router-dom';
import { Layout} from './components/Layout';
import Home from "./Home";
import Post from "./Post";
import Login from './Login';
function App() {
const [isAuthenticated, setIsAuthenticated] = useState (false)
console.log(isAuthenticated + "1");
function auth () { setIsAuthenticated (true);
console.log(isAuthenticated + "2");
}
console.log(isAuthenticated + "3");
const PrivateRoute = ({ component: Component, ...rest}) => (
<Route {...rest} render={(props)=>(
isAuthenticated === true
? <Component {...props}/>
: <Redirect to='/login' />
)}/>
)
return (<Router>
<div className="App">
<Nav />
<Layout>
<Switch>
<Route path="/" exact component={Home} />
<Route path="/about" component={About} />
<Route path="/creater" component={Creater} />
<Route auth={auth} path="/login" component={Login} />
<PrivateRoute isAuthenticated={isAuthenticated} path="/post" component={Post} />
</Switch>
</Layout>
</div>
</Router>
);
}
export default App;
Login:
import React, { useState } from "react";
import axios from 'axios';
var bcrypt = require('bcryptjs');
function Login({auth}) {
const [login, setLogin] = useState ({
adminname: "",
password: "",
});
function onChangeAdminname (event) {
setLogin({adminname: event.target.value,
password: login.password})
}
function onChangePassword (event) {
setLogin({adminname: login.adminname,
password: event.target.value})
}
function onSubmit ({event }) {
event.preventDefault();
const admin = login.adminname
const logpassword = login.password
axios.get('http://localhost:5000/admins', {
params: {
adminname: admin
}
})
.then(function (response) {
var pw = (response.data);
console.log(response.data);
bcrypt.compare(logpassword, pw[0].password, function(err, result){
if (result === true) {
console.log(auth);
auth();
window.location.pathname = "/post";
} else {
if(!alert("Admin name or password was incorrect, please try again")){window.location.reload();}
}
});
})
.catch(function (error) {
console.log(error);
});
}
return (
<div class="row">
<div class="col-sm-8">
<div class="card">
<div class="card-body">
<form
onSubmit={onSubmit}
>
<div class="form-group">
<input className="form-control"
type="text"
placeholder="Admin Name"
value={login.adminname}
onChange={onChangeAdminname}
name="adminmame"/>
</div>
<div class="form-group">
<input type="password"
className="form-control"
placeholder="Password"
value={login.password}
onChange={onChangePassword}
name="password"/>
</div>
<button value="POST" type="submit" className="btn btn-dark">Login</button>
</form>
</div>
</div>
</div>
</div>
)
}
export default Login;
post:
import React, { useState } from "react";
import axios from 'axios';
import {authenticated} from './Login';
import './App.css';
import DatePicker from 'react-datepicker';
import "react-datepicker/dist/react-datepicker.css";
function Post() {
const [postDate, setPostDate] = useState(new Date());
const [post, setPost] = useState({
title: "",
blog: "",
date: postDate,
});
function onChangeTitle(event) {
setPost({
title: event.target.value,
blog : post.blog,
date: post.date})
}
function onChangeBlog(event) {
setPost({
title: post.title,
blog : event.target.value,
date: post.date})
}
function onChangeDate(date) {
setPostDate(date);
}
function onSubmit(event) {
event.preventDefault();
axios.post('http://localhost:5000/posts/add', post)
.then(res => console.log(res.data));
window.location = '/';
}
return (
<div >
<h3>Compose a new post :D</h3>
<form onSubmit={onSubmit}>
<div className="form-group">
<input type="text"
required
className="form-control form-control-lg"
placeholder="Title"
value={post.title}
onChange={onChangeTitle}/>
</div>
<div>
<textarea type="text"
required
className="form-control form-control-lg"
rows="10"
placeholder="Tell a story"
value={post.blog}
onChange={onChangeBlog} ></textarea>
</div>
<div className="form-group">
<label>Date: </label>
<div>
<DatePicker
selected={postDate}
onChange={onChangeDate}/>
</div>
</div>
<div className="form-group">
<input type="submit" value="POST" className="btn btn-primary"/>
</div>
</form>
</div>
)
}
export default Post;
As far as I am concerned Bcrypt is not supported in ReactJS however can be used in NodeJS.
The browser supported version for Bcrypt is npm install bcryptjs
check their docs here:https://www.npmjs.com/package/bcryptjs
login undefined
I am getting login as undefined, whenever I click the login button it was working fine before I created AppRoutes.js and moved some of the routes into that file.
TypeError: login is not a function
here is the code structure.
this is the main file where app is started and login route is put here inside the AppRoutes component.
app.js
import React, { Fragment, useEffect } from 'react'
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'
import Navbar from './components/layout/Navbar'
import Landing from './components/layout/Landing'
import Alert from './components/layout/Alert'
import { loadUser } from './actions/auth'
import { Provider } from 'react-redux'
import setAuthToken from './utils/setAuthToken'
import store from './store'
import './App.css'
import AppRoutes from './components/routing/AppRoutes'
if (localStorage.token) {
setAuthToken(localStorage.token)
}
const App = () => {
useEffect(() => {
store.dispatch(loadUser())
}, [])
return (
<Provider store={store}>
<Router >
<Fragment>
<Navbar />
<Alert />
<Switch>
<Route exact path='/' component={Landing} />
<Route component={AppRoutes} />
</Switch>
</Fragment>
</Router>
</Provider>
)
}
export default App
2.AppRoutes.js
import React, { Fragment } from 'react'
import { Register } from '../auth/Register'
import { Login } from '../auth/Login'
import Dashboard from '../dashboard/Dashboard'
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'
import PrivateRoute from './PrivateRoute'
import { NotFound } from '../layout/NotFound'
import store from '../../store'
import { Provider } from 'react-redux'
const AppRoutes = () => {
return (<Fragment>
<Switch>
<Route exact path='/register' component={Register} />
<Route exact path='/login' component={Login} />
<PrivateRoute path='/dashboard' component={Dashboard} >
</PrivateRoute>
<Route component={NotFound} />
</Switch>
</Fragment>
)
}
export default AppRoutes
auth.js
export const login = (email, password) => async dispatch => {
const config = {
headers: {
'Content-Type': 'application/json'
}
}
const body = JSON.stringify({ email, password })
try {
const res = await axios.post('/api/auth', body, config)
if (res?.data?.token) {
dispatch({
type: LOGIN_SUCCESS,
payload: res.data
})
dispatch(loadUser())
}
else {
dispatch(setAlert(res.data.msg, 'success'))
}
} catch (error) {
const errors = error.response.data.errors
if (errors) {
errors.forEach(error => dispatch(setAlert(error.msg, 'danger')))
}
dispatch({
type: LOGIN_FAIL
})
}
}
4.Login.js
import React, { Fragment, useState } from 'react'
import { connect } from 'react-redux'
import PropTypes from 'prop-types'
import { login } from '../../actions/auth'
import { Link, Redirect } from 'react-router-dom'
import store from '../../store'
export const Login = ({ isAuthenticated, login }) => {
const [formData, setFormData] = useState({
email: '',
password: ''
})
const { email, password } = formData
const onChange = e => setFormData({ ...formData, [e.target.name]: e.target.value })
const onSubmit = e => {
e.preventDefault()
console.log(typeof login)
login(email, password)
}
//redirect if logged in
if (isAuthenticated) {
return <Redirect to='/dashboard' />
}
return (
<Fragment>
<div className="m-5">
<div className="row justify-content-center">
<div className="col-md-4">
<div className="card shadow-lg o-hidden border-0 my-5">
<div className="card-body p-0">
<div>
<div className="p-5">
<div className="text-center">
<h4 className="text-dark mb-4">Welcome Back!</h4>
</div>
<form className="user" onSubmit={e => onSubmit(e)}>
<div className="form-group">
<input className="form-control form-control-user" type="email" placeholder="Email Address" name="email" value={email} onChange={e => onChange(e)} required />
</div>
<div className="form-group">
<input className="form-control form-control-user" type="password"
placeholder="Password"
name="password"
minLength="6"
value={password} onChange={e => onChange(e)}
/>
</div>
<div className="form-group">
<div className="custom-control custom-checkbox small">
<div className="form-check">
<input className="form-check-input custom-control-input" type="checkbox" id="formCheck-1" />
<label className="form-check-label custom-control-label" htmlFor="formCheck-1">Remember Me</label>
</div>
</div>
</div><button className="btn btn-dark btn-block text-white btn-user" type="submit">Login</button>
<hr />
</form>
<div className="text-center"><Link to="/register" className="small" href="register.html">Create an Account!</Link></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</Fragment >
)
}
Login.propTypes = {
login: PropTypes.func.isRequired,
isAuthenticated: PropTypes.bool
}
const mapStateToProps = state => ({
isAuthenticated: state.auth.isAuthenticated
})
export default connect(mapStateToProps, { login })(Login)
I am not able to figure out whether it is related to the route structure that i changed or is there a bigger problem that I am missing out on.
You have imported Login a named import in AppRoutes, whereas the connected component with Login was a default export which is why you see the issue
Change
import { Login } from '../auth/Login'
to
import Login from '../auth/Login'
I am attempting to learn reactjs and I've looked up so many different resources from using react-route to react-route-dom but everything I've tried doesn't work as everything says it does so I am not sure what I am misssing.
I have a class component called LoginForm which renders the form and handles all of the logic for submitting to API and handling the response.
The api request is working and I successfully check that the login is valid, I then want to redirect to another page called dashboard.html.
Below is my component class
import React from 'react'
import * as api from '../JSFuncs/APIManager'
import 'react-router-dom'
class LoginForm extends React.Component {
constructor(props) {
super(props);
this.state = {
username: '',
password: '',
show_notice: false,
error_msg: ''
};
this.handleUsernameChange = this.handleUsernameChange.bind(this);
this.handlePasswordChange = this.handlePasswordChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleUsernameChange(event) {
this.state.username = event.target.value;
this.setState(this.state);
}
handlePasswordChange(event) {
this.state.password = event.target.value;
this.setState(this.state);
}
handleSubmit(event) {
event.preventDefault();
this.props.history.push("dashboard.html");
this.state.show_notice = true;
this.setState(this.state);
const postArray = {
username: this.state.username,
password: this.state.password
};
let comp = this;
api.sendRequest(postArray, "admin/authenticator.php", "submitLogin").then(function(result){
alert(JSON.stringify(result));
if (result.result === 0)
{
if (result.data === 0) //Login OK
{
comp.history.pushState(null, 'dashboard.html');
//comp.props.history.push('/dashboard.html');
}
comp.setState(comp.state);
}
else
{
comp.state.password = '';
comp.state.error_msg = 'An error occurred with the DB';
comp.setState(comp.state);
}
comp.state.show_notice = true;
comp.setState(comp.state);
})
}
render() {
const style = this.state.show_notice === false ? {display: 'none'} : {};
const { location, history } = this.props
return (
<section className="h-100">
<div className="container h-100">
<div className="d-flex align-items-center justify-content-center h-100">
<div className="d-flex flex-column align-self-center">
<LoginStatus style={style} error_msg={this.state.error_msg} />
<form onSubmit={this.handleSubmit} className='form-horizontal align-self-center'>
<div className='form-group row'>
<label htmlFor='txtUsername' className='col-sm-2 col-form-label'>Username: </label>
<div className='col-sm-9'>
<input type='text' className='form-control' id='txtUsername' value={this.state.username}
placeholder='Your Username' onChange={this.handleUsernameChange}/>
</div>
</div>
<div className='form-group row'>
<label htmlFor='txtPassword' className='col-sm-2 col-form-label'>Password: </label>
<div className='col-sm-9'>
<input type='password' className='form-control' id='txtPassword' value={this.state.password}
placeholder='Your password' onChange={this.handlePasswordChange}/>
</div>
</div>
<div className='formButtonContainer'>
<button className='btn-primary'>Login</button>
</div>
</form>
</div>
</div>
</div>
</section>
);
}
}
class LoginStatus extends React.Component
{
render(){
const className = this.props.error_msg === '' ? 'alert-info' : 'alert-warning';
const msg = this.props.error_msg === '' ? 'You\'ve successfully logged in' : this.props.error_msg;
return(
<div style={this.props.style} className={'alert ' + className}>
{msg}
</div>
)
}
}
export default LoginForm
In the response of handleSubmit I check if the login result is 0 and then I am using comp.history.pushState (comp is declared to be this so its in scope of the promise).
I've tried pushState and push from other examples, but I get the same type of error. I've also tried comp.state.history.push but no luck. I login successfully and show the alert box when I do the history push I get the following:
TypeError: Cannot read property 'push' of undefined
I'm very new to react so apologise if this is a simple answer but I can't seem to get my hand around how this works from everything I've googled.
In your App.js you should manage pages with routes:
import {BrowserRouter, Route, Switch} from "react-router-dom";
import { createBrowserHistory } from "history";
import {LoginForm} from './components/LoginForm';
import {Dashboard} from './components/Dashboard';
const history = createBrowserHistory();
class App extends Component {
constructor(props) {
super(props);
console.log(props)
}
render() {
path="/" is your home or main page
path="/dashboard" is your dashboard
return (
<BrowserRouter>
<div>
<Switch>
<Route path="/" render={(props) => <LoginForm props={history} {...props} /> } exact />
<Route path="/dashboard" render={(props) => <Dashboard props={history} {...props} /> }/>
</Switch>
</div>
</BrowserRouter>
)
then in your LoginForm you can
export class LoginForm extends Component {
constructor(props) {
super(props);
console.log(props)
}
go_dashboard = (e) => {
this.props.history.push("/dashboard");
}
This will then Switch to your Dashboard component.
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.