2017-07-17 114 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