Reputation: 1641
I'm new to react and toying with a sign-up form. My render method always displays the current state of user.name
, user.email
and the error
attribute is always flagged appropriately.
However, within my bound methods (considerSubmit
, validateEmail
, etc..) console.log(this.state)
outputs my default state, not the current state.
What am I missing here? I thought that .bind(this)
would synchronize the state amongst all methods.
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import {withStyles, createStyleSheet} from 'material-ui/styles';
import TextField from 'material-ui/TextField';
import Button from 'material-ui/Button';
import Dialog, {
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
} from 'material-ui/Dialog';
import Slide from 'material-ui/transitions/Slide';
const popsicle = require('popsicle');
const styleSheet = createStyleSheet('RegistrationProgress', {
root: {
maxWidth: 400,
flexGrow: 1,
},
});
class RegistrationProgress extends React.Component {
constructor(props) {
super(props);
this.state = {
user: {
name: null,
isNameValid: null,
email: null,
isEmailValid: null
},
notice: {
title: null,
message: null,
open: false,
}
};
}
handleRequestClose() {
let noticeState = this.state.notice;
noticeState.open = false;
this.setState({notice: noticeState});
};
considerSubmit(event) {
const isSubmitAction = event.key === 'Enter' || event.type === 'click';
if (isSubmitAction) {
let userState = this.state.user;
let formReady = (userState.isNameValid && userState.isEmailValid);
if (!formReady) {
this.showNotice("Hold on a sec!", "Make sure your first and last name is provided as well as a proper email address.");
return;
}
var RegistrationProgress = this;
var element = document.querySelector('meta[name="csrf-token"]');
var csrf_token = element && element.getAttribute("content");
console.log(userState, userState.name,this.state.user)
popsicle.request({
method: 'POST',
url: '/register',
body: {
name: userState.name,
email: userState.email,
_token: csrf_token
},
headers: {
'X-XSRF-TOKEN': csrf_token
}
})
.use(popsicle.plugins.parse('json'))
.then(function (res) {
console.log(res.status) // => 200
console.log(res.body) //=> { ... }
console.log(res.get('Content-Type')) //=> 'application/json'
RegistrationProgress.showNotice("Yeehaw!", "Account created! Confirm your email to login.");
})
.catch(function(error){
RegistrationProgress.showNotice("Uh-oh.", "Looks like our server hiccuped when handling your request. Try again.")
});
}
return event;
}
showNotice(title = "Whoa!", message) {
this.setState({
notice: {
title: title,
message: message,
open: true
}
})
}
validateName(event) {
const nameRule = /^(([A-Za-z]+[\-\']?)*([A-Za-z]+)?\s)+([A-Za-z]+[\-\']?)*([A-Za-z]+)?$/;
let registerName = (event.target.value).trim();
let userState = this.state.user;
userState.isNameValid = nameRule.test(registerName);
console.log(userState)
this.setState({user: userState})
}
validateEmail(event) {
const emailRule = /^([a-zA-Z0-9_\-\.]+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,5})$/;
let registerEmail = (event.target.value).trim();
let userState = this.state.user;
userState.isEmailValid = emailRule.test(registerEmail);
this.setState({
user: userState
})
}
render() {
const classes = this.props.classes;
return (
<div className="register-form" onKeyPress={this.considerSubmit.bind(this)}>
<TextField id="name" name="name" label="Full Name" type="text" defaultValue={this.state.user.name}
className={classes.input}
error={RegistrationProgress.getErrorState(this.state.user.isNameValid)}
helperText="" onChange={(event) => this.validateName(event)} marginForm
/>
<br/>
<TextField id="email" name="email" label="Email" type="email" defaultValue={this.state.user.email}
className={classes.input}
error={RegistrationProgress.getErrorState(this.state.user.isEmailValid)}
helperText="" onChange={(event) => this.validateEmail(event)} marginForm
/>
<br />
<Button raised color="primary" className={'register-button ' + classes.button}
onClick={(event) => this.considerSubmit(event)}>
Sign Up
</Button>
<Dialog open={this.state.notice.open} transition={Slide}
onRequestClose={this.handleRequestClose.bind(this)}>
<DialogTitle>
{this.state.notice.title}
</DialogTitle>
<DialogContent>
<DialogContentText>
{this.state.notice.message}
</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={this.handleRequestClose.bind(this)} color="primary">
Got it!
</Button>
</DialogActions>
</Dialog>
</div>
);
}
static getErrorState(value) {
return (!value && value !== null);
}
}
RegistrationProgress.propTypes = {
classes: PropTypes.object.isRequired,
};
export default withStyles(styleSheet)(RegistrationProgress);
Upvotes: 3
Views: 10570
Reputation: 1464
Your handlers for the components are just binding 'this' to the handler methods but not invoking them.
You can bind 'this' in your constructor, or make your handler functions as 'fat arrow' functions (this is bound automatically then). Then, be sure to set the handlers correctly in your components:
constructor:
constructor(props) {
super(props);
this.state = {
user: {
name: null,
isNameValid: null,
email: null,
isEmailValid: null
},
notice: {
title: null,
message: null,
open: false,
}
};
this.considerSubmit.bind(this);
this.handleRequestClose.bind(this);
this.handleRequestClose.bind(this);
}
render:
render() {
const classes = this.props.classes;
return (
<div className="register-form" onKeyPress={this.considerSubmit()}>
<TextField id="name" name="name" label="Full Name" type="text" defaultValue={this.state.user.name}
className={classes.input}
error={RegistrationProgress.getErrorState(this.state.user.isNameValid)}
helperText="" onChange={(event) => this.validateName(event)} marginForm
/>
<br/>
<TextField id="email" name="email" label="Email" type="email" defaultValue={this.state.user.email}
className={classes.input}
error={RegistrationProgress.getErrorState(this.state.user.isEmailValid)}
helperText="" onChange={(event) => this.validateEmail(event)} marginForm
/>
<br />
<Button raised color="primary" className={'register-button ' + classes.button}
onClick={(event) => this.considerSubmit(event)}>
Sign Up
</Button>
<Dialog open={this.state.notice.open} transition={Slide}
onRequestClose={this.handleRequestClose()}>
<DialogTitle>
{this.state.notice.title}
</DialogTitle>
<DialogContent>
<DialogContentText>
{this.state.notice.message}
</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={this.handleRequestClose())} color="primary">
Got it!
</Button>
</DialogActions>
</Dialog>
</div>
);
}
Upvotes: 0