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.
Related
So im trying to pass some props from my login component to the payment component with the user's info, to do this I update as shown below:
import React, { Component } from 'react';
import Login from './login';
import { BrowserRouter, Route, Routes } from 'react-router-dom';
import Pay from './payment';
export default class app extends Component {
constructor(props) {
super(props);
this.state = {
LoggedInState: false,
LoggedInUser: [],
SellingProduct: [],
Users: [],
generalproducts: []
}
}
render() {
return (
<BrowserRouter>
<NavBar logged={this.state.LoggedInUser} />
<div className="container-fluid">
<Routes>
<Route path='/' element={<HomePage products={this.generalproducts} />} />
<Route path='/shoppingcart' element={<ShopCart logged={this.state.LoggedInState} paymentHandle={this.onBuyFromCart} products={this.state.generalproducts} />} />
<Route path='/login' element={<Login onLogged={this.onLogInSuccesful} />} />
<Route path='/Payment' element={<Pay ProductInProcess={this.state.SellingProduct} user={this.state.LoggedInUser} />} />
<Route path='/Camera' element={<Cam />} />
<Route path='*' element={<Nomatch />} />
</Routes>
</div>
</BrowserRouter>
)
}
onBuyFromCart = (prod) => {
console.log('in');
this.setState({ SellingProduct: prod });
console.log('dada');
}
onLogInSuccesful = (userlogged) => {
this.setState({ LoggedInState: true, LoggedInUser: userlogged });
console.log('AppLoggedinState', this.state.LoggedInState);
console.log('AppLoggedinuser', this.state.LoggedInUser);
};
componentDidMount = async () => {
var response = await fetch("http://localhost:5000/products");
var ConvertedProducts = await response.json();
this.setState({ generalproducts: ConvertedProducts });
}
}
It works fine from login component to the parent component but when payment tab is displayed I get no values using props, for example:
import React, { Component } from "react";
import { Link } from "react-router-dom";
export default class Pay extends Component {
constructor(props) {
super(props);
this.state = {
productSaled: this.props.ProductInProcess,
info: [],
stored: false
};
}
render() {
return (
<button className="card p-3" onClick={() => { this.onStoredCardClick(); }}>
<div className="img-box">
<img src="https://www.freepnglogos.com/uploads/mastercard-png/file-mastercard-logo-svg-wikimedia-commons-4.png"
alt="" />
</div>
<div className="number">
<label className="fw-bold">{this.props.user.CreditCardnum}</label>
</div>
<div className="d-flex align-items-center justify-content-between">
<small><span className="fw-bold">Expiry date:</span><span>{this.props.user.CreditCardDate}</span></small>
<small><span className="fw-bold">Name:</span><span>{this.props.user.CreditCardName}</span></small>
</div>
</button>
);
}
onStoredCardClick = () => {
this.setState({ stored: true });
console.log('state ', this.state);
console.log(' props', this.props);
}
componentDidMount = () => {
console.log(this.state);
}
}
gives me nothing as seen here:payment info
And login component is:
import React, { Component } from "react";
export default class Login extends Component {
constructor(props) {
super(props);
this.state = { email: "", password: "", message: "" };
}
render() {
return (
<div>
<h4 className="m-1 p-2 border-bottom">Login</h4>
{/* Email starts */}
<div className="form-group form-row">
<label className="col-lg-4">Email:</label>
<input
type="text"
className="form-control"
value={this.state.email}
onChange={(event) => {
this.setState({ email: event.target.value });
}}
/>
</div>
{/* Email ends */}
{/* Password starts */}
<div className="form-group form-row">
<label className="col-lg-4">Password:</label>
<input
type="password"
className="form-control"
value={this.state.password}
onChange={(event) => {
this.setState({ password: event.target.value });
}}
/>
</div>
{/* Password ends */}
<div className="text-right">
{this.state.message}
<button className="btn btn-primary m-1" onClick={this.onLoginClick}>
Login
</button>
</div>
</div>
);
} //end of render
//Executes when the user clicks on Login
onLoginClick = async () => {
var response = await fetch(
`http://localhost:5000/users?id=${this.state.email}&password=${this.state.password}`,
{ method: "GET" }
);
var body = await response.json();
if (body.length > 0) {
//success
var response = await fetch(
`http://localhost:5000/users/${this.state.email}`,
{ method: "GET" }
);
var body = await response.json();
console.log(body);
this.setState({
message: <span className="text-success">Successfully Logged-in</span>,
});
this.props.onLogged(body);
//window.location = '\payment';
} else {
//error
this.setState({
message: (
<span className="text-danger">Invalid login, please try again</span>
),
});
}
};
}
this is the console log form AppState
And this is the console log from Payment
Well, after a couple months I found out that when using window.locaionthe page will refresh al previous values for the props given, therefore, nothing will arrive to the component being loaded. To prevent this I changed to the usage of useNavigate and the hook useContext this solved the shortage of arriving information to the other children components. I am not good with the terminology of react yet so excuse for it.
The log in component now look like this (please focus on the useNavigate and useContext as for it is what solved my error):
import React, { Component, useState, useContext } from "react";
import { UserContext } from "./UserContext";
import { useNavigate } from "react-router-dom";
export default function Login(props) {
const [State, setState] = useState({
Email: "",
password: "",
message: "",
});
const history = useNavigate();
const [GeneralState, setGeneralState] = useContext(UserContext);
let onLoginClick = async () => {
const response1 = await fetch(
`http://localhost:5000/users?id=${State.Email}&password=${State.password}`,
{ method: "GET" }
);
const body1 = await response1.json();
if (body1.length > 0) {
//success
const response = await fetch(
`http://localhost:5000/users/${State.Email}`,
{ method: "GET" }
);
const body = await response.json();
setState({
message: <span className="text-success">Successfully Logged-in</span>,
});
setGeneralState({
...GeneralState,
LoggedInState: true,
LoggedInUser: body,
})
history("/shoppingcart", { replace: true });
} else {
//error
setState({
message: (
<span className="text-danger">Invalid login, please try again</span>
),
});
}
};
return (
<div>
<h4 className="m-1 p-2 border-bottom">Login</h4>
{/* Email starts */}
<div className="form-group form-row">
<label className="col-lg-4">Email:</label>
<input
type="text"
className="form-control"
value={State.Email}
onChange={(event) => {
setState({ ...State, Email: event.target.value });
}}
/>
</div>
{/* Email ends */}
{/* password starts */}
<div className="form-group form-row">
<label className="col-lg-4">password:</label>
<input
type="password"
className="form-control"
value={State.password}
onChange={(event) => {
setState({ ...State, password: event.target.value });
// console.log(GeneralState)
}}
/>
</div>
{/* password ends */}
<div> <a href="/register" style={{ fontSize: 12 }}>No tienes cuenta? Registrate</a></div>
<div className="text-right">
{State.message}
<button className="btn btn-primary m-1" onClick={onLoginClick}>
Login
</button>
</div>
</div>
);
//Executes when the user clicks on Login
}
And the UserContext component, from where useContext takes the info, is this one:
import { createContext } from "react";
export const UserContext = createContext();
As for the other components like app component, shown in the question statement at the start of this thread, it is necessary to also add the useContext statements so that your whole project will work under the same context.
A new component is returned after login, but both the login component and the Home Component are seen on the page. I need to return the Home Componenet without Login Component. I am new to React and still trying to understand return and routes in React.
This is my pages component which returns either Login or Home based on this.state.redirect1.
import React, { Component } from 'react';
import { Redirect } from 'react-router-dom';
import '../../App.css';
import Login from '../Login';
import Home from '../Home';
import Header from './Header';
import Footer from './Footer';
class Pages extends Component {
constructor(props) {
super(props)
this.state = {
redirect: false,
}
}
handleClick() {
this.state.redirect = true;
console.log(this.state.redirect);
}
changeRedirect =() =>{
this.state.redirect = true;
console.log(this.state.redirect);
this.forceUpdate()
}
renderRedirect = () => {
if(this.props.redirect1){
return <Home/>
}
else{
return <Login/>
}
}
render() {
return (
<div className="mh-100 PgWidth">
{this.renderRedirect()}
</div>
)
}
}
export default Pages
Below is my Login, Home and App Components
Login.js
import React, { Component } from 'react'
import Axios from 'axios';
import Pages from './common/Pages'
import { Redirect } from 'react-router-dom';
class Login extends Component {
constructor(props) {
super(props)
this.state = {
username: '',
password: '',
redirect: false
}
}
handleUsername = (event) => {
this.setState({
username: event.target.value
})
}
handlePassword = (event) => {
this.setState({
password: event.target.value
})
}
renderRedirect = () => {
if (this.state.redirect) {
console.log("from render redirect");
return <Pages redirect1={this.state.redirect} />
}
}
formSubmitHandler = event => {
let formdata = new FormData();
formdata.append("username", this.state.username);
formdata.append("password", this.state.password);
Axios.post("/auth/local",{
"name":this.state.username,
"password": this.state.password
})
.then(res => {
if (res) {
console.log(res);
this.setState({ redirect: true });
}
})
event.preventDefault() // used to keep the form data as entered even after the submit
}
render() {
const { username, password } = this.state
return (
<div className="p-5">
{ this.renderRedirect() }
<h3>Sign-In</h3>
<form onSubmit={this.formSubmitHandler}>
<div className="form-group row">
<label htmlFor="inputEmail3" className="col-sm-2 col-form-label">Username</label>
<div className="col-sm-10">
<input type="text" value={username} onChange={this.handleUsername}
className="form-control" id="inputEmail3" placeholder="Username" />
</div>
</div>
<div className="form-group row">
<label htmlFor="inputPassword3" className="col-sm-2 col-form-label">Password</label>
<div className="col-sm-10">
<input type="password" value={password} onChange={this.handlePassword}
className="form-control" id="inputPassword3" placeholder="Password" />
</div>
</div>
<div className="form-group row">
<div className="col-sm-2">Checkbox</div>
<div className="col-sm-10">
<div className="form-check">
<input className="form-check-input" type="checkbox" id="gridCheck1" />
<label className="form-check-label" htmlFor="gridCheck1">
Example checkbox
</label>
</div>
</div>
</div>
<div className="form-group row">
<div className="col-sm-10">
<button type="submit" onClick={this.formSubmitHandler} className="btn btn-primary">Sign in</button>
</div>
</div>
</form>
</div>
)
}
}
export default Login
Home.js
import React, { Component } from 'react'
import '../App.css';
export class Home extends Component {
componentDidMount(){
console.log("home component mount");
}
render() {
return (
<div>
<h1>The page has been routed</h1>
</div>
);
}
}
export default Home
App.js
import React, { Component } from 'react';
import './App.css';
import Header from './components/common/Header';
import Footer from './components/common/Footer';
import Pages from './components/common/Pages';
class App extends Component {
render() {
return (
<div className="App container-fluid bg-light w-75">
<div className="row justify-content-md-center">
<div className="col m-0 p-0">
<Header/>
<div className="">
<Pages/>
</div>
<Footer/>
</div>
</div>
</div>
);
}
}
export default App;
Issue is in this line:
{ this.renderRedirect() }
Once redirect will be true, it will render the Home page first then the Login component.
Solution to you problem is: Manage the redirect bool in Page component only, and pass a function to update to Login component to update its value and decide the component based on that.
Changes:
1- defined redirect: false in Pages component.
2- A function to change its value in Pages component:
updateValue = (value) => {
this.setState({ redirect: true })
}
3- Pass function to Login component:
renderRedirect = () => {
if(this.props.redirect1) {
return <Home/>
}
else{
// =====> here
return <Login updateValue={this.updateValue} />
}
}
4- After successful Login call this function and render Home Component:
formSubmitHandler = event => {
event.preventDefault();
let formdata = new FormData();
formdata.append("username", this.state.username);
formdata.append("password", this.state.password);
Axios.post("/auth/local",{
"name":this.state.username,
"password": this.state.password
})
.then(res => {
if (res) {
// =======> here
this.props.updateValue(true)
}
})
}
5- Remove this line from Login Component:
{ this.renderRedirect() }
Problem with current code:
You are managing the login session using state variable, so after refreshing the page it will again show the login page not home page. So better to store the value in localStorage and read its value in page component to decide the initial value of redirect.
Suggestion:
Instead of deciding the route/component using boolean, better to use react-router for better structuring/managing the app.
Try return it in render:
import React, { Component } from 'react';
import { Redirect } from 'react-router-dom';
import '../../App.css';
import Login from '../Login';
import Home from '../Home';
import Header from './Header';
import Footer from './Footer';
class Pages extends Component {
constructor(props) {
super(props)
this.state = {
redirect: false,
}
}
handleClick() {
this.state.redirect = true;
console.log(this.state.redirect);
}
changeRedirect =() =>{
this.state.redirect = true;
console.log(this.state.redirect);
this.forceUpdate()
}
render() {
if(this.props.redirect){
return (
<div className="mh-100 PgWidth">
<Home/>
</div>
)
} else {
return (
<div className="mh-100 PgWidth">
<Login/>
</div>
)
}
}
export default Pages;
You can do it like this
<div className="mh-100 PgWidth">
{this.props.redirect1&&<Home/>}
{!this.props.redirect1&&<Login />}
</div>
But, the best way to do this is using react router and managing the global react state
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 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
I have two components. These components are located on different routes. 'CreateItem' component gives me possibility to create new items. I store new items to array. Array will include new created items. I want send this modified array to component 'Main' where I will iterate those items and display them as list.
Here is my code:
1) index.js file:
import React, { Component } from 'react';
import { render } from 'react-dom';
import { BrowserRouter, Route } from 'react-router-dom'
import {Main} from "./components/Main"
import {CreateItem} from "./components/CreateItem"
import {CurrentItem} from "./components/CurrentItem"
render(
<BrowserRouter>
<div>
<Route exact path="/" component={Main}/>
<Route path="/create_item" component={CreateItem}/>
<Route path="/item" component={CurrentItem}/>
</div>
</BrowserRouter>,
document.getElementById('app')
);
2) Main.js
import React from 'react';
import { withRouter } from 'react-router-dom';
import { Route, browserHistory } from 'react-router-dom';
export class Main extends React.Component {
render(){
const ToCreateItemPageButton = () => (
<Route render={({ history}) => (
<button type='button' onClick={() => { history.push('/create_item') }}>Move to create item page!</button>
)}
/>
)
return (
<div>
<h1>Main Page</h1>
<ToCreateItemPageButton/>
</div>
);
}
}
3) CreateItem.js
import React from 'react';
import { Route, browserHistory } from 'react-router-dom';
export class CreateItem extends React.Component {
constructor(props) {
super(props);
this.state = {
mainArray: [],
item: {},
item_id: 0,
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({item: {item_id: this.state.item_id,
name:event.target.value}});
}
handleSubmit(event) {
if (this.state.item.name.length > 0) {
this.state.mainArray.push(this.state.item);
this.state.item_id = this.state.item_id + 1;
let data = JSON.stringify(this.state.mainArray);
localStorage.setItem('mainObject', data);
this.setState(
{mainArray : this.state.mainArray,
item_id : this.state.item_id,}
);
event.preventDefault();
}
}
render(){
const ToMainPageButton = () => (
<Route render={({ history}) => (
<button type='button' onClick={() => { history.push('/') }}>Move to main page!</button>
)}
/>
)
return (
<div>
<h1>Create new item</h1>
<ToMainPageButton/>
<form onSubmit={this.handleSubmit}>
<label>
<input type="text" value={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
</div>
);
}
}
So all I want is to have possibility to transfer my mainArray from 'CreateItem' component to 'Main' component.
You could redirect and send data like that:
this.props.history.push({
pathname: '/target-path',
data: [/*your data*/]
});
and receive it on the target component so:
const { data } = this.props.location;
Short answer - Yes it's possible using container component like in fiddle example.
So the idea is to keep you array of items in a container state and pass it to "iterated" component as well as a callback for handling incoming item.
// container component
class Container extends React.Component {
constructor(props){
super(props);
this.state = {
array: ['Hello', 'Stack', 'Overflow']
}
this.handleOnAdd = this.handleOnAdd.bind(this)
}
handleOnAdd(item){
this.setState({
array: [...this.state.array, item]
})
}
render() {
return (
<div>
// pass shared props to "display" component
<ChildOneDisplay items={this.state.array} />
// pass a callback to CreateItem component
<ChildTwoAdd onAdd={this.handleOnAdd} />
</div>
);
}
}
// display component
class ChildTwoAdd extends React.Component{
constructor(props){
...
this.handleAdd = this.handleAdd.bind(this)
}
handleAdd(){
this.props.onAdd(this.state.item);
...
}
render(){
return(
<div>
<input
name="item"
type="text"
onChange={this.handleChange}
value={this.state.item}
/>
<button onClick={this.handleAdd}>Add Me</button>
</div>
)
}
}
So all you need is to wrap your two routes with a container component and pass props to both of them as i did in this example.
// So your container should look like the following one
render(){
return (
<div>
<Route exact path="/" render={() => <Main items={this.state.array}}/>
<Route path="/create_item" render={() => <CreateItem onAdd={this.handleAdd}/>}/>
</div>
)
}
// And render it as the following
<BrowserRouter>
<Container />
<Route path="/item" component={CurrentItem}/>
</BrowserRouter>
Moreover i suggest looking at redux - this is the library for managing your app state.
Thanks!