Submit login form made with React components - javascript

I am creating a login form with some input components and a button component.
SignIn.js
class SignIn extends Component {
render() {
return (
<article className="br2 ba dark-gray b--black-10 mv4 w-100 w-50-m w-30-l h-auto h-auto-l h-auto-m h-auto-m h-auto-ns shadow-5 center">
<main className="pa4 black-80">
<legend className="f2 fw6 ph0 mh0 tc">Sign In</legend>
<VerticalInputComponent id_name="signin_email" input_label="Email" />
<VerticalInputComponent id_name="signin_password" input_label="Password" />
<div className="tc mt3 mt3-l mt3-m mt3-ns">
<ButtonComponent button_value="Sign In" />
</div>
</main>
</article>
);
}
}
VerticalInputComponent.js
class VerticalInputComponent extends Component {
render() {
return(
<form className="pl4 pr4 pt4 pb2 black-80 w-100 measure">
<div className="measure">
<label htmlFor={ this.props.id_name } className="f6 b db mb2">{ this.props.input_label }
{ this.props.isOptional
? <span className="normal black-60">(optional)</span>
: null
}
</label>
<input id={ this.props.id_name } className="input-reset ba b--black-20 pa2 mb2 db w-100" type="text" aria-describedby="name-desc" />
</div>
</form>
)
}
}
ButtonComponent.js
class ButtonComponent extends Component {
render() {
return (
<div>
<input
className="b ph3 pv2 input-reset ba b--black bg-transparent grow pointer f6 dib"
type="submit"
value={ this.props.button_value }
/>
</div>
);
}
}
The question is how do I submit the email and password on a post request? I know how to do it on normal HTML but I don't know how to do it in React. I am guessing I need to use Redux or state but I don't know the syntax. The random examples that I read doesn't make sense to me at least for now.

There is no need for Redux or even a state to submit a form.
You should wrap the entire form element in a single form, even if they are nested in custom components. You had 2 forms, one for each input, but you're only wanting to send 1 signin POST request.
Also dont forget to include the name attribute in your form input elements because these are the property names the server will see in your POST request.
Note that e.preventDefault(); is to prevent the window from refreshing and we don't want that in a single-page application.
class VerticalInputComponent extends React.Component {
render() {
return(
<div className="measure">
<label htmlFor={ this.props.id_name } className="f6 b db mb2">{ this.props.input_label }
{ this.props.isOptional
? <span className="normal black-60">(optional)</span>
: null
}
</label>
<input id={ this.props.id_name } name={this.props.id_name} className="input-reset ba b--black-20 pa2 mb2 db w-100" type="text" aria-describedby="name-desc" />
</div>
)
}
}
class ButtonComponent extends React.Component {
render() {
return (
<div>
<input
className="b ph3 pv2 input-reset ba b--black bg-transparent grow pointer f6 dib"
type="submit"
value={ this.props.button_value }
/>
</div>
);
}
}
class SignIn extends React.Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleSubmit(e) {
e.preventDefault();
const data = new FormData(e.target);
for (var pair of data.entries()) {
console.log(pair[0] + ': ' + pair[1]);
}
fetch('/someURL', {
method: 'POST',
body: data,
});
}
render() {
return (
<article className="br2 ba dark-gray b--black-10 mv4 w-100 w-50-m w-30-l h-auto h-auto-l h-auto-m h-auto-m h-auto-ns shadow-5 center">
<main className="pa4 black-80">
<legend className="f2 fw6 ph0 mh0 tc">Sign In</legend>
<form onSubmit={this.handleSubmit}>
<VerticalInputComponent id_name="signin_email" input_label="Email" />
<VerticalInputComponent id_name="signin_password" input_label="Password" />
<div className="tc mt3 mt3-l mt3-m mt3-ns">
<ButtonComponent button_value="Sign In" />
</div>
</form>
</main>
</article>
);
}
}
// Render it
ReactDOM.render(
<SignIn/>,
document.getElementById("react")
);
<div id="react"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

Related

How to transfer data between two child component in react js?

Actually I'm creating a front-end in which I am taking a mobile number as input on 1st page then after checking mobile number I am moving to OTP page. In OTP page I am taking otp as input and have to send both otp and mobile number to the backend. I am able to pass the otp but dont know how to pass the mobile number as I have taken it as input in the previous page.
Here is Signup Component which will take mobile number input
import React from 'react';
import './Signup.css';
class Signup extends React.Component {
constructor(props){
super(props);
this.state={
mobile:''
}
}
onMobileChange = (event) => {
this.setState({mobile: event.target.value})
}
onSubmitSignup = () => {
fetch('https://cors-anywhere.herokuapp.com/http://8080/signup/checkMobile',{
method:'post',
headers:{'Content-Type':'application/json'},
body: JSON.stringify({
mobile:this.state.mobile
})
})
.then(response => response.json())
.then(data =>{
if(data.content === 'OK'){
this.props.loadNewUser(this.state.mobile);
this.props.onRouteChange('otp','nonav');
}
})
// this.props.onRouteChange('otp','nonav');
}
render(){
const { onRouteChange} = this.props;
return(
<div className='container'>
<div className='mt6'>
<img src={require('./logo.png')} className='logoimg' alt='logo'/>
</div>
<h3 className='text-center b' style={{font:"Montserrat"}}>FOODVIRAAM</h3>
<div>
<article className="br3 ba dark-gray b--white mv4 w-100 w-50-m w-25-l mw6 shadow-6 center">
<main className="pa4 black-80">
<div className="measure">
<fieldset id="sign_up" className="ba b--transparent ph0 mh0">
<div className="mt1">
<label className="db fw5 lh-copy f3" htmlFor="email-address" style={{font:"Montserrat"}}>Enter your mobile number</label>
<input
className="pa2 input-reset ba bg-transparent hover-bg-black bw1 br2 w-100"
type="number"
name="mobile"
id="mobile"
style={{borderColor:"#ffde59",lineHeight:"28px"}}
onChange={this.onMobileChange}
/>
</div>
</fieldset>
<div className="tr">
<input
onClick={this.onSubmitSignup}
className="pv2 input-reset ba b--white bg-transparent grow pointer f3 dib" style={{font:"Montserrat"}} type="submit" value="Send OTP"/>
</div>
</div>
</main>
</article>
</div>
<h5 className="tc mt5" style={{font:"Montserrat"}}>{"#HighwayKaHygienicPitStop"}</h5>
</div>
);
}
}
export default Signup;
OTP component In which I will take OTP as input and then have to send otp and mobile number on Submit
import React from 'react';
import './Signup.css';
class Otp extends React.Component{
constructor(props){
super(props);
this.state={
otp:''
}
}
onOtpChange = (event) => {
this.setState({otp: event.target.value})
}
onSubmitOtp = () => {
console.log(this.props.mobile);
fetch('https://cors-anywhere.herokuapp.com/http://8080/signup/validateOtp',{
method:'post',
headers:{'Content-Type':'application/json'},
body: JSON.stringify({
mobile:this.props.mobile,
otp:this.state.otp
})
})
.then(response => response.json())
.then(data =>{
if(data.content === 'OK'){
// this.props.loadNewUser(this.state.otp);
this.props.onRouteChange('createprofile','nonav');
}
})
this.props.onRouteChange('otp','nonav');
}
render(){
const { mobile,onRouteChange} = this.props;
return(
<div className='container'>
<div className='mt6'>
<img src={require('./logo.png')} className='logoimg' alt='logo'/>
</div>
<h3 className='text-center b' style={{font:"Montserrat"}}>FOODVIRAAM</h3>
<div>
<article className="br3 ba dark-gray b--white mv4 w-100 w-50-m w-25-l mw6 shadow-6 center">
<main className="pa4 black-80">
<div className="measure">
<fieldset id="sign_up" className="ba b--transparent ph0 mh0">
<div className="mt1">
<label className="db fw5 lh-copy f3" htmlFor="email-address" style={{font:"Montserrat"}}>Verify OTP</label>
<input
className="pa2 input-reset ba bg-transparent hover-bg-black bw1 br2 w-100"
type="number"
name="mobile-number"
id="mobile-number"
style={{font:"Montserrat", borderColor:"#ffde59",lineHeight:"28px"}}
onChange={this.onOtpChange}
/>
</div>
</fieldset>
<div className="tr">
<input
onClick={this.onSubmitOtp}
className="pv2 input-reset ba b--white bg-transparent grow pointer f3 dib" style={{font:"Montserrat"}} type="submit" value=""/>
</div>
</div>
</main>
</article>
</div>
<h5 className="tc mt5" style={{font:"Montserrat"}}>{"#HighwayKaHygienicPitStop"}</h5>
</div>
);
}
}
export default Otp;
And this is the parent class
class App extends Component {
constructor(props){
super(props);
this.state={
route:'signup',
route1:'nonav',
newuser:{
mobile:''
}
}
}
loadNewUser = (mobile)=>{
this.setState({user: {
mobile:mobile
}})
console.log(mobile);
}
onRouteChange = (route, route1) =>{
this.setState({route:route});
this.setState({route1:route1});
}
render(){
return (
<div className="App">
{this.state.route1==='nav'
? <div>
<Navigation onRouteChange={this.onRouteChange}/>
{ this.state.route==='editmnc'
? <EditMNC parentMethod={this.onRouteChange}>{this.props.children}</EditMNC>
:<Revenue onRouteChange={this.onRouteChange}/>
}
</div>
}
: <div>
{ this.state.route==='signup'
? <Signup loadNewUser={this.loadNewUser} onRouteChange={this.onRouteChange}/>
: <div>
{ this.state.route==='otp'
? <Otp mobile={this.state.newuser.mobile} onRouteChange={this.onRouteChange}/>
: <div>
{ this.state.route==='createprofile'
? <CreateProfile onRouteChange={this.onRouteChange} />
: <div>
{ this.state.route==='signin'
? <Signin onRouteChange={this.onRouteChange} />
: <AddItem onRouteChange={this.onRouteChange}/>
}
</div>
}
</div>
}
</div>
}
</div>
}
</div>
);
}
}
Use localStorage or Cookies to store your phone number on one page and on the next page, you can easily retrieve the data by whatever medium you choose. Since storing on either of them persist your data, you don't need to worry about an accidental refresh of the page.
Don't use Redux or Context API, as they don't persist the data.
Example :-
Using the localStorage API
// storing the phone number on your first page.
localStorage.setItem('$$NAMESPACE__phone_number', phoneNumber)
// getting the phone number on your second.
const phoneNumber = localStorage.getItem('$$NAMESPACE__phone_number')
Use Redux it's a bit complicated but It is used when you need to transfer data from child to parent,
You can also get the data that you sent by props to child and got a return value
https://redux.js.org

Why css file of one component interacted with the css file of another component in ReactJS? How to handle it?

I am trying to make a website template with Reactjs. In the Jumbotron section i make subscription form and in the home section User Entry form. But the css of one component interacted with another's one. How can i handle it?
[1]: https://i.stack.imgur.com/Wd4OQ.png
User EntryJs:-
import React, { Component } from 'react'
import './User Entry.css'
class Form extends Component {
initialState = {
name: "",
age: "",
job: ""
}
state = this.initialState
changeHandler = event => {
const { name, value } = event.target
this.setState({
[name]: value
})
}
render() {
const { name, job, age } = this.state
return (
<form className="form-inline">
<div className="row">
<div className="col-md-3">
<div className="form-group">
<label htmlFor="name">Name:-</label>
<input type="text"
className="form-control"
name="name"
id="name"
value={name}
autoFocus
onChange={this.changeHandler} />
</div>
</div>
<div className="col-md-3">
<div className="form-group">
<label htmlFor="age">Age:-</label>
<input type="text"
className="form-control"
name="age"
id="age"
value={age}
autoFocus
onChange={this.changeHandler} />
</div>
</div>
<div className="col-md-3">
<div className="form-group">
<label htmlFor="job">Job:-</label>
<input type="text"
className="form-control"
name="job"
id="job"
value={job}
autoFocus
onChange={this.changeHandler} />
</div>
</div>
<div className="col-md-3"></div>
</div>
</form>
)
}
}
export default Form
Header JS:-
import React, { Component } from 'react'
import './Header.css'
import { Link, withRouter } from "react-router-dom";
class Header extends Component {
constructor(props) {
super(props)
this.state = {
email: ""
}
}
submitHandler = event => {
event.preventDefault();
alert(`Subscribed Email is : ${this.state.email}`);
}
changeHandler = event => {
this.setState({
email: event.target.value
})
}
render() {
return (
// Navbar Starts
<div>
<div className="row navbar">
<Link to="/" style={{textDecoration:'none'}}><div className="col-md-2 logo">ReactApp</div></Link>
<div className="col-md-6"></div>
<Link to="/" style={{textDecoration:'none'}}> <div className="col-md-1 link"> Home</div> </Link>
<Link to="/about" style={{textDecoration:'none'}}> <div className="col-md-1 link"> About</div> </Link>
<Link to="/counter" style={{textDecoration:'none'}}> <div className="col-md-1 link"> Counter </div></Link>
<Link style={{textDecoration:'none'}}><div className="col-md-1 link">Login</div></Link>
</div>
<div className="jumbotron text-center">
<h1>React-App</h1>
<p>We specialize in <strong>Web Development</strong></p>
{/* Subscribing form starts*/}
<form className="form-inline subscribingForm" onSubmit={this.submitHandler}>
<div className="input-group">
<input type="email"
className="form-control"
value={this.state.email}
onChange={this.changeHandler}
size="80"
placeholder="Email..."
required />
<div className="input-group-btn">
<input type="submit" value="Subscribe" className="subscribingBtn" />
</div>
</div>
</form>
{/* Subscribing form closes*/}
</div>
</div>
)
}
}
export default withRouter(Header);
Where is the .css file loaded, in the root component? It probably is loaded globally and is used on every component.Better use JSS (https://cssinjs.org/?v=v10.3.0)
In general react transpiles all the css and add it in to tag.
And as result you one file css conflicts with other.
If you want to avoid this, you can use modular css.
https://create-react-app.dev/docs/adding-a-css-modules-stylesheet/

How to access a function from another component that is located in another js file by clicking a button in create-react-app?

I have two files index.js and map.js. In map.js I have Kartta component, that contains a leaflet map and a method fetchAll() that creates markers on the map from the coordinates that it gets from API, which in this case is test.json. It works fine if I put the method inside componentDidMount(), it creates the markers on load. However I want to create those markers by clicking the button "Haku", which is located inside Sidebar component in index.js.
Here is map.js
import React, { Component } from 'react';
import L from 'leaflet';
import { Map, Marker, Popup, TileLayer } from 'react-leaflet';
import { fetchAll } from './search';
const position = [62.241581, 25.758742];
class Kartta extends Component {
state = {
kohteet: []
}
componentDidMount() {
this.fetchAll();
}
fetchAll = () => {
console.log("täällä");
fetch('test.json')
.then(res => res.json())
.then((data) => {
this.setState({ kohteet: data })
})
.catch(console.log(this.state.kohteet))
}
iconSize = (iconName) => {
if (iconName == 'tree.png') {
return 30, 30
}
else {
return 15, 30
}
}
render() {
return (
<div id="mapid" className="h-100 w-100">
<Map center={position} zoom={7}>
<button onClick={this.haeKaikki}>Hae</button>
<TileLayer
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
attribution="© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors"
/>
{this.state.kohteet.map((kohde) => (
<Marker key={'key' + kohde.id} position={[kohde.lon, kohde.lat]} icon={
new L.Icon({
iconUrl: require('../img/' + kohde.icon),
iconSize: new L.Point(this.iconSize(kohde.icon)),
id: kohde.id + kohde.icon
})
}>
<Popup>
<h1>{kohde.name}</h1>
<p>{kohde.desc}</p>
</Popup>
</Marker>
))}
</Map>
</div>
)
}
}
export default Kartta
Here is index.js
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import './css/main.css';
import 'bootstrap/dist/js/bootstrap.bundle.js';
import 'leaflet/dist/leaflet.css';
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome';
import { faSearch, faInfoCircle } from '#fortawesome/free-solid-svg-icons';
import Kartta from './components/map';
// Yläpalkki
class Navbar extends React.Component {
render() {
return (
<nav id="nav-bar" className="navbar navbar-expand-lg navbar-dark bg-primary">
<a id="nav-bar-a0" className="navbar-brand" href="/">MeijänMetsät</a>
<button id="toggle-search-btn" type="button" href="#sidebar" data-toggle="collapse" className="btn btn-primary">
<FontAwesomeIcon icon={faSearch} />
<span> Haku</span>
</button>
<ul id="nav-bar-ul0" className="navbar-nav mr-auto">
</ul>
<div id="nav-bar-div0" className="dropdown">
<button id="nav-bar-button0" className="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">Kirjaudu
<span id="nav-bar-span0" className="caret"></span></button>
<div id="dropdown-div0" className="p-2 dropdown-menu dropdown-menu-right" style={{"minWidth":"350px"}}>
<form id="dropdown-form0">
<div id="dropdown-div1" className="form-group">
<label id="dropdown-label0" htmlFor="exampleInputEmail1">Sähköposti</label>
<input id="dropdown-input0" type="email" className="form-control" id="exampleInputEmail1" aria-describedby="emailHelp" placeholder="Syötä sähköposti" />
</div>
<div id="dropdown-div2" className="form-group">
<label id="dropdown-label1" htmlFor="exampleInputPassword1">Salasana</label>
<input id="dropdown-input1" type="password" className="form-control" id="exampleInputPassword1" placeholder="Salasana" />
</div>
<div id="dropdown-div3" className="row">
<button id="dropdown-button0" type="submit" className="ml-3 btn btn-primary">Kirjaudu</button>
<button id="dropdown-button2" type="submit" className="ml-2 btn btn-primary">Rekiströidy</button>
<button id="dropdown-button1" type="submit" className="ml-2 btn btn-secondary">Facebook</button>
</div>
</form>
</div>
</div>
</nav>
);
}
}
// Sivupalkki
class Sidebar extends React.Component {
render() {
return (
<div className="p-2 collapse in" id="sidebar">
<div className="list-group panel" id="sidebar-div0">
<form id="sidebar-form0">
<div id="sidebar-div01" className="form-group active">
<label id="sidebar-label0" htmlFor="exampleInputEmail1">Kohteen nimi</label><span> </span>
<FontAwesomeIcon icon={faInfoCircle} className="pointer dropdown-toggle" data-toggle="dropdown" alt="Hakuohjeet" />
<div id="search-info" className="p-2 dropdown-menu dropdown-menu-right">
<p>Hae kirjoittamalla tägejä</p>
</div>
<div className="row">
<div className="col-7 ml-3 p-0">
<input type="text" className="form-control" id="searchByName" aria-describedby="emailHelp" placeholder="Syötä kohteen nimi" />
</div>
<button id="sidebar-button0" type="submit" className="btn btn-primary ml-2 col-3" onClick={() => Kartta.fetchAll}>Haku</button>
</div>
</div>
</form>
<div id="sidebar-div02" className="dropdown">
<a id="sidebar-button1" className="btn btn-light dropdown-toggle p-0 thaku" type="button" data-toggle="dropdown">Tarkennettu haku
<span id="sidebar-span0" className="caret"></span></a>
<div id="sidebar-div020" className="p-0 dropdown-menu border-0 mt-2 w-100 h-100">
<form id="sidebar-form1">
<div id="sidebar-div0200" className="form-group p-0">
<label id="sidebar-label1" htmlFor="exampleInputEmail1">Paikkakunta</label>
<input id="sidebar-input1" type="text" className="form-control" placeholder="Syötä paikkakunta" />
</div>
<div id="ch-div0" className="row pl-3">
<label id="lbl-location">Sijainti</label>
<input id="ch-location" className="mt-2 ml-2" type="checkbox" aria-label="Checkbox for following text input" />
</div>
<div className="input-group mb-3">
<div className="input-group-prepend">
<label className="input-group-text" htmlFor="inputGroupSelect01">Palvelut</label>
</div>
<select className="custom-select" id="inputGroupSelect01">
<option defaultValue>Valitse...</option>
<option value="1">Kakkapaikka</option>
<option value="2">Pissapaikka</option>
<option value="3">Kaljapaikka</option>
</select>
</div>
<div id="dropdown-div3" className="row p-0">
<button id="dropdown-button0" type="submit" className="ml-3 btn btn-primary">Tarkennettu haku</button>
</div>
</form>
</div>
</div>
</div>
</div>
);
}
}
// Sisältö
class Content extends React.Component {
render() {
return (
<div id="main-container" className="container-fluid h-100 p-0">
<Navbar />
<div id="container0" className="row h-100 w-100 m-0 wrapper">
<Sidebar />
<div id="container02" className="col h-100 w-100 p-0">
<Kartta />
</div>
</div>
</div>
);
}
}
ReactDOM.render(<Content />, document.getElementById('root'));
The button "Haku" has onClick={() => Kartta.fetchAll}, but it does not do anything, it isn't even accessing the fetchAll() function. The function works perfectly if I create the button on the map, but I don't want to do that, the button has to be on the Sidebar as the plan is to use a search word in the future.
Thank you!
you need to create a prop e.g. createmap:booleanin Kartta component. Now in index.js firstly you need to create a state e.g. createmap:boolean (initially set to false) and upon Haku button click you need to set the state:
this.setState({
creatmap:true;
});
you need to include Katta component JSX in index.js render() function e.g.
<Kartta createmap = {this.state.createmap} />
Now in Kartta component on componentDidMount()you can check createmap' prop and based on its value call the functionfetchAll()`:
public componentDidMount() {
if(this.prop.createmap) {
fetchAll();
}
}
what this will do is causing rerendering due to setting state upon button click and will call 'fetchAll()' function if createMap is found true
Hope this helps.
EDIT:
Don't forget to use export keyword with your Kartta component class so you can import it in index.js to create its JSX in render():
export default class Kartta extends Component { ... }
EDIT 2
In your navbar component class initialize state in constructor:
export default class NavBar extends Component {
constructor(props) {
super(props);
this.state: {
createmap: false;
}
}
}
your Kartta component class:
export default class Kartta extends Component {
constructor(props) {
super(props);
}
componentDidMount() {
if(this.props.createmap) {
fetchAll();
}
}

Why I cannot type continuously in react Input field when passing values to another component using props

I am trying to pass values through props from one component to another.
Parent component is InstructorLoginForm and child component is InstructorLoginFormComponent
Everything works fine but the problem is I cannot type in input text field continuously
I try to type username, it types one letter and then it kind loses the focus into the input field, so I have to again click on the input field and type another(single) letter and again focus loses
This is same for the password field too.
Hers is my parent component InstructorLoginForm.jsx
import React, { Component } from "react";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import InstructorProfile from "./instructor-profile";
import InstructorLoginFormComponent from "./instructor-login-form-component";
export default class InstructorLoginForm extends Component {
constructor(props) {
super(props);
this.state = {
username: "",
password: ""
};
this.onChangeUsername = this.onChangeUsername.bind(this);
this.onChangePassword = this.onChangePassword.bind(this);
this.handleOnClick = this.handleOnClick.bind(this);
}
onChangeUsername(e) {
this.setState({
username: e.target.value
});
}
onChangePassword(e) {
this.setState({
password: e.target.value
});
}
handleOnClick (){
e.preventDefault();
this.props.history.push(`/instructor/${this.state.username}`);
}
render() {
return (
<Router>
<Switch>
<Route
exact
path="/login"
component={props => (
<InstructorLoginFormComponent
{...props}
username = {this.state.username}
password = {this.state.password}
handleOnClick = {this.handleOnClick}
onChangeUsername = {this.onChangeUsername}
onChangePassword = {this.onChangePassword}
/>
)}
/>
<Route
path={"/instructor/:instructorId"}
component={InstructorProfile}
/>
</Switch>
</Router>
);
}
}
And here is my child component InstructorLoginFormComponent.jsx
import React, { Component } from "react";
import { Link } from "react-router-dom";
export default class InstructorLoginFormComponent extends Component {
constructor(props) {
super(props);
}
componentDidMount(){
console.log(this.props);
}
render() {
return (
<div className="container h-100" style={{ marginTop: 100 }}>
<div className="d-flex justify-content-center h-100">
<div className="user_card bg-dark">
<div className="d-flex justify-content-center">
</div>
<div
className="d-flex justify-content-center form_container"
style={{ marginTop: 0 }}
>
<form>
<div className="input-group mb-3">
<div className="input-group-append">
<span className="input-group-text bg-info">
<i className="fa fa-user" />
</span>
</div>
<input
value={this.props.username}
onChange={this.props.onChangeUsername}
type="text"
name="username"
className="form-control input_user"
placeholder="username"
/>
</div>
<div className="input-group mb-2">
<div className="input-group-append">
<span className="input-group-text bg-info">
<i className="fa fa-lock" />
</span>
</div>
<input
value={this.props.password}
onChange={this.props.onChangePassword}
type="password"
name="passwordbutton"
className="form-control input_user"
placeholder="password"
/>
</div>
<div className="form-group">
<div className="custom-control custom-checkbox">
<input
type="checkbox"
className="custom-control-input"
id="customControlInline"
/>
<label
className="custom-control-label"
htmlFor="customControlInline"
style={{ color: "#ffffff" }}
>
Remember me
</label>
</div>
</div>
</form>
</div>
<div className="d-flex justify-content-center mt-3 login_container">
<button
// to={`/instructor/${this.props.username}`}
onClick={this.props.handleOnClick}
type="button"
className="btn login_btn bg-info"
>
Login
</button>
</div>
</div>
</div>
</div>
);
}
}
Can someone help me why this happens and how to resolve it?
When you type text, the state of the parent component updates and render function calls again. You used
<Route component={...} />
it calls React.createElement at every render, so old child component unmounts and router creates new instance, focus loses.
To fix this issue use
<Route render={<InstructorLoginFormComponent ... />} />
it also provides {match, location, history} props to child, but does not unmount it when parent state changed.
Sorry to put it this way, but this is poor architecture along with a few mistakes in syntax.
You should have all routes in your App.js file and everything else in your Component file (should actually be a Container.js file and a Component.js file, but for another time).
You only need one onChange event (note change to the function structure).
The below behaves as it should.
Please note the handleOnClick should have (e), that should be throwing an error.
Please note password name in the input has been corrected to password, from password button
App.js;
import React, { Component } from "react";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import InstructorProfile from "./instructor-profile";
import InstructorLoginFormComponent from "./instructor-login-form-component";
export default class App extends Component {
render() {
return (
<Router>
<Switch>
<Route
exact
path="/login"
component={InstructorLoginFormComponent }
/>
<Route
path={"/instructor/:instructorId"}
component={InstructorProfile}
/>
</Switch>
</Router>
);
}
}
and InstructorLoginFormComponent;
import React, { Component } from "react";
import { Link } from "react-router-dom";
export default class InstructorLoginFormComponent extends Component {
constructor(props) {
super(props)
this.state = {
username: "",
password: ""
}
this.onChange = this.onChange.bind(this)
this.handleOnClick = this.handleOnClick.bind(this)
}
onChange(e) {
this.setState({
[e.target.name]: e.target.value
})
}
handleOnClick (e) {
e.preventDefault()
this.props.history.push(`/instructor/${this.state.username}`)
}

render() {
const { username, password } = this.state
return (
<div className="container h-100" style={{ marginTop: 100 }}>
<div className="d-flex justify-content-center h-100">
<div className="user_card bg-dark">
<div className="d-flex justify-content-center">
</div>
<div
className="d-flex justify-content-center form_container"
style={{ marginTop: 0 }}
>
<form>
<div className="input-group mb-3">
<div className="input-group-append">
<span className="input-group-text bg-info">
<i className="fa fa-user" />
</span>
</div>
<input
value={username}
onChange={this.onChange}
type="text"
name="username"
className="form-control input_user"
placeholder="username"
/>
</div>
<div className="input-group mb-2">
<div className="input-group-append">
<span className="input-group-text bg-info">
<i className="fa fa-lock" />
</span>
</div>
<input
value={password}
onChange={this.onChange}
type="password"
name="password"
className="form-control input_user"
placeholder="password"
/>
</div>
<div className="form-group">
<div className="custom-control custom-checkbox">
<input
type="checkbox"
className="custom-control-input"
id="customControlInline"
/>
<label
className="custom-control-label"
htmlFor="customControlInline"
style={{ color: "#ffffff" }}
>
Remember me
</label>
</div>
</div>
</form>
</div>
<div className="d-flex justify-content-center mt-3 login_container">
<button
// to={`/instructor/${this.props.username}`}
onClick={this.props.handleOnClick}
type="button"
className="btn login_btn bg-info"
>
Login
</button>
</div>
</div>
</div>
</div>
);
}
}

Rendering new component on click in react

I'm practicing react and trying to render a new component on click of a button. Here the first page is email and the component i want to render contains password page.
class App extends React.Component {
passwordpage(){
return(
<form>
<div className="mainapp">
<h2> Password</h2>
<input type='Password' className="inputpassword" placeholder='Enter Password' required/>
<div>
<button type="submit" className="loginbutton">Next</button>
</div>
</div>
</form>
);
};
render() {
return (
<form>
<div className="mainapp">
<h2>Email Id</h2>
<input type='email' ref='enteremail'className="inputemail" placeholder='Enter Username' required/>
<div>
<button type="submit" onClick={this.props.passwordpage} className="loginbutton">Next</button>
</div>
</div>
</form>
);
}
}
ReactDOM.render(<App/>,document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.8/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.8/react-dom.min.js"></script>
<div id="app"></div>
The simplest is to have the password page already prepared in your render(),
and to show/hide it depending on the component state, that is mutated by the onClick handler, something along those lines:
showPasswordPage() {
this.setState({showPassword: true });
}
render() {
const passwordPage = (<form>
<div className="mainapp">
<h2> Password</h2>
<input type='Password' className="inputpassword" placeholder='Enter Password' required/>
<div>
<button type="submit" className="loginbutton">Next</button>
</div>
</div>
</form>);
const mainForm = (<form>
<div className="mainapp">
<h2>Email Id</h2>
<input type='email' ref='enteremail'className="inputemail" placeholder='Enter Username' required/>
<div>
<button type="submit" onClick={this.showPasswordPage} className="loginbutton">Next</button>
</div>
</div>
</form>);
return { this.state.showPassword ? passwordPage : mainForm };
I usually keep some variables in state and change them based on user action.
So in your case I have stored the current active page e.g usernamePage and when user clicks next I show another page in your case it is passwordPage.
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
isPasswordPage : false,
isUsernamePage : true,
username : "",
password : ""
};
this.enablePasswordPage = this.enablePasswordPage.bind(this);
}
enablePasswordPage() {
this.setState({
isPasswordPage : true,
isUsernamePage : false
});
}
passwordpage(){
return(
<form>
<div className="mainapp">
<h2> Password</h2>
<input type='Password' className="inputpassword" placeholder='Enter Password' required/>
<div>
<button type="submit" className="loginbutton">Next</button>
</div>
</div>
</form>
);
};
render() {
var usernameComp = (
<form>
<div className="mainapp">
<h2>Email Id</h2>
<input type='email' ref='enteremail'className="inputemail" placeholder='Enter Username' required/>
<div>
<button onClick={this.enablePasswordPage} className="loginbutton">Next</button>
</div>
</div>
</form>
);
return (
<div>
{ this.state.isUsernamePage ? usernameComp : null }
{ this.state.isPasswordPage ? this.passwordpage() : null }
</div>
);
}
}
ReactDOM.render(<App/>,document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.8/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.8/react-dom.min.js"></script>
<div id="app"></div>
What you need to do is to make use of react-router and then create separate components for each of the Page that you want to display. That is the best possible way to achieve what you want to do.
You components will look something like
class Home extends React.Component {
render() {
return (
<div>{this.props.children}</div>
)
}
}
class App extends React.Component {
handleClick = (e) => {
e.stopPropagation();
browserHistory.push('/passwordPage');
}
render() {
return (
<form>
<div className="mainapp">
<h2>Email Id</h2>
<input type='email' ref='enteremail'className="inputemail" placeholder='Enter Username' required/>
<div>
<button className="loginbutton" onClick={this.handleClick}>Next</button>
</div>
</div>
</form>
);
}
}
class PasswordPage extends React.Component {
render() {
return (
<form>
<div className="mainapp">
<h2> Password</h2>
<input type='Password' className="inputpassword" placeholder='Enter Password' required/>
<div>
<button type="submit" className="loginbutton">Next</button>
</div>
</div>
</form>
)
}
}
ReactDOM.render(
<Router history={browserHistory}>
<Route path="/" component={Home}>
<IndexRoute component={App} />
<Route path="/passwordPage" component={PasswordPage} />
</Route>
</Router>
)
Look at the react-router docs here

Categories

Resources