2017-07-17 33 views
1

我是新来的用反应表单进行反应和打扰。我的渲染方法始终显示user.name,user.email的当前状态,并且error属性始终标记为正确。console.log this.state未显示反应中的当前状态

但是,在我的绑定方法(considerSubmitvalidateEmail,等..)console.log(this.state)输出我的默认状态,而不是当前状态。

我在这里错过了什么?我认为.bind(this)会同步所有方法之间的状态。

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); 
+0

我建议你在用脂肪箭头或绑定绑定一致函数,你可以很容易地用'()=> this.handleRequestClose()'替换'this.handleRequestClose.bind(this)'。而不是'let userState = this.state.user;'使用'let userState = {... this.state.user};'来防止状态的直接变异, –

+1

另外我想这个问题可能和https一样://stackoverflow.com/questions/41278385/this-setstate-doesnt-mutate-state-immediately/41278440#41278440。另请参阅https://stackoverflow.com/questions/42811882/what-is-the-meaning-of-this-syntax-x-in-reactjs/42811937#42811937如果你想知道'let userState = {... this.state.user};'意思是 –

+0

感谢您的反馈。我一定会考虑这些建议。回复@ Finbarr-ob的回答,请参阅我的评论。 – TylersSN

回答

0

组件的处理程序只是将“this”绑定到处理程序方法但不调用它们。

您可以在构造函数中绑定'this',或者将您的处理函数作为'胖箭头'函数(然后自动绑定)。然后,一定要设置正确的处理程序在你的组件:

构造:

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() { 
    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> 
    ); 
} 
+0

感谢您的建议。我用一个绑定向构造函数添加了每一个方法,但是在validateName中的'console.log(userState)'仍然为name和email对象输出null,尽管它们在render中正确同步。我想我应该更深入地探究“调用方法” – TylersSN

+0

为什么这并不明显,我不知道。我的行为就像defaultValue保持名称状态同步一样。 validateName()只是验证并将isNameValid设置为true或false。没有任何事情设定名称的状态。 – TylersSN