2016-06-24 11 views
6

ReactとReduxを使用して複数のステップ登録フォームを作成しようとしています。制御されるタイプのテキストの制御されない入力

次のように主なコンポーネントは次のとおりです。

import React, {PropTypes} from 'react'; 
import {connect} from 'react-redux'; 
import {bindActionCreators} from 'redux'; 
import * as actionCreators from '../../actions/actionCreators'; 
import countries from '../../data/countries'; 

import RegistrationFormStepOne from './registrationFormStepOne'; 
import RegistrationFormStepTwo from './registrationFormStepTwo'; 
import RegistrationFormStepThree from './registrationFormStepThree'; 
import RegistrationFormStepFour from './registrationFormStepFour'; 

class RegistrationPage extends React.Component { 
    constructor(props) { 
     super(props); 

     this.state = { 
      user: Object.assign({}, this.props.userData), 
      fileNames: {}, 
      selectedFile: {}, 
      icons: { 
       idCard: 'upload', 
       statuten: 'upload', 
       blankLetterhead: 'upload', 
       companyPhoto: 'upload' 
      }, 
      step: 1, 
      errors: {} 
     }; 

     this.setUser = this.setUser.bind(this); 
     this.onButtonClick = this.onButtonClick.bind(this); 
     this.onButtonPreviousClick = this.onButtonPreviousClick.bind(this); 
     this.changeCheckboxState = this.changeCheckboxState.bind(this); 
     this.onFileChange = this.onFileChange.bind(this); 
     this.routerWillLeave = this.routerWillLeave.bind(this); 
    } 

    componentDidMount() { 
     this.context.router.setRouteLeaveHook(this.props.route, this.routerWillLeave); 
    } 

    routerWillLeave(nextLocation) { 
     if (this.state.step > 1) { 
      this.setState({step: this.state.step - 1}); 
      return false; 
     } 
    } 

    getCountries(){ 
     return countries; 
    } 


    setUser(event) { 
     const field = event.target.name; 
     const value = event.target.value; 

     let user = this.state.user; 
     user[field] = value; 
     this.setState({user: user}); 

    } 

    validation(){ 
     const user = this.state.user; 
     const languageReg = this.props.currentLanguage.default.registrationPage; 
     let formIsValid = true; 
     let errors = {}; 

     if(!user.companyName){ 
      formIsValid = false; 
      errors.companyName = languageReg.companyNameEmpty; 
     } 

     if(!user.btwNumber){ 
      formIsValid = false; 
      errors.btwNumber = languageReg.btwNumberEmpty; 
     } 

     if(!user.address){ 
      formIsValid = false; 
      errors.address = languageReg.addressEmpty; 
     } 

     if(!user.country){ 
      formIsValid = false; 
      errors.country = languageReg.countryEmpty; 
     } 

     if(!user.zipcode){ 
      formIsValid = false; 
      errors.zipcode = languageReg.zipcodeEmpty; 
     } 

     if(!user.place){ 
      formIsValid = false; 
      errors.place = languageReg.placeEmpty; 
     } 


     if(!user.firstName){ 
      formIsValid = false; 
      errors.firstName = languageReg.firstnameEmpty; 
     } 



     this.setState({errors: errors}); 
     return formIsValid; 
    } 

    onFileChange(name, event) { 
     event.preventDefault(); 
     let file = event.target.value; 

     let filename = file.split('\\').pop(); //We get only the name of the file 
     let filenameWithoutExtension = filename.replace(/\.[^/.]+$/, ""); //We get the name of the file without extension 

     let user = this.state.user; 
     let fileNames = this.state.fileNames; 
     let selectedFile = this.state.selectedFile; 
     let icons = this.state.icons; 

     switch (name.btnName) { 
      case "idCard" : 
       fileNames[name.btnName] = filenameWithoutExtension; 
       //Check if file is selected 
       if(file){ 
        selectedFile[name.btnName] = "fileSelected"; 
        user["idCardFile"] = true; 
        icons["idCard"] = "check"; 
       }else{ 
        selectedFile[name.btnName] = ""; 
        user["idCardFile"] = false; 
        icons["idCard"] = "upload"; 
       } 
       break; 
      case "statuten" : 
       fileNames[name.btnName] = filenameWithoutExtension; 

       //Check if file is selected 
       if(file){ 
        selectedFile[name.btnName] = "fileSelected"; 
        user["statutenFile"] = true; 
        icons["statuten"] = "check"; 
       }else{ 
        selectedFile[name.btnName] = ""; 
        user["statutenFile"] = false; 
        icons["statuten"] = "upload"; 
       } 
       break; 
      case "blankLetterhead" : 
       fileNames[name.btnName] = filenameWithoutExtension; 

       //Check if file is selected 
       if(file){ 
        selectedFile[name.btnName] = "fileSelected"; 
        user["blankLetterheadFile"] = true; 
        icons["blankLetterhead"] = "check"; 
       }else{ 
        selectedFile[name.btnName] = ""; 
        user["blankLetterheadFile"] = false; 
        icons["blankLetterhead"] = "upload"; 
       } 
       break; 
      default: 
       fileNames[name.btnName] = filenameWithoutExtension; 
       //Check if file is selected 
       if(file){ 
        selectedFile[name.btnName] = "fileSelected"; 
        user["companyPhotoFile"] = true; 
        icons["companyPhoto"] = "check"; 
       }else{ 
        selectedFile[name.btnName] = ""; 
        user["companyPhotoFile"] = false; 
        icons["companyPhoto"] = "upload"; 
       } 
     } 

     this.setState({user: user, fileNames: fileNames, selectedFile: selectedFile, icons: icons}); 
    } 

    changeCheckboxState(event) { 
     let chcName = event.target.name; 
     let user = this.state.user; 

     switch (chcName) { 
      case "chcEmailNotificationsYes": 
       user["emailNotifications"] = event.target.checked; 
       break; 
      case "chcEmailNotificationsNo": 
       user["emailNotifications"] = !event.target.checked; 
       break; 
      case "chcTerms": 
       if(typeof this.state.user.terms === "undefined"){ 
        user["terms"] = false; 
       }else{ 
        user["terms"] = !this.state.user.terms; 
       } 

       break; 
      case "chcSmsYes": 
       user["smsNotifications"] = event.target.checked; 
       break; 
      default: 
       user["smsNotifications"] = !event.target.checked; 
     } 
     this.setState({user: user}); 
     this.props.actions.userRegistration(this.state.user); 
    } 

    onButtonClick(name, event) { 
     event.preventDefault(); 
     this.props.actions.userRegistration(this.state.user); 
     switch (name) { 
      case "stepFourConfirmation": 
       this.setState({step: 1}); 
       break; 
      case "stepTwoNext": 
       this.setState({step: 3}); 
       break; 
      case "stepThreeFinish": 
       this.setState({step: 4}); 
       break; 
      default: 
       if(this.validation()) { 
        this.setState({step: 2}); 
       } 
     } 
    } 


    onButtonPreviousClick(){ 
     this.setState({step: this.state.step - 1}); 
    } 

    render() { 
     const languageReg = this.props.currentLanguage.default.registrationPage; 

     console.log(this.state.user); 
     let formStep = ''; 
     let step = this.state.step; 
     switch (step) { 
      case 1: 
       formStep = (<RegistrationFormStepOne user={this.props.userData} 
                onChange={this.setUser} 
                onButtonClick={this.onButtonClick} 
                countries={this.getCountries(countries)} 
                errors={this.state.errors} 
                step={step}/>); 
       break; 
      case 2: 
       formStep = (<RegistrationFormStepTwo user={this.props.userData} 
                onChange={this.setUser} 
                onButtonClick={this.onButtonClick} 
                onButtonPreviousClick={this.onButtonPreviousClick} 
                errors={this.state.errors}/>); 
       break; 
      case 3: 
       formStep = (<RegistrationFormStepThree user={this.props.userData} 
                 onFileChange={this.onFileChange} 
                 onButtonClick={this.onButtonClick} 
                 onButtonPreviousClick={this.onButtonPreviousClick} 
                 errors={this.state.errors} 
                 fileNames={this.state.fileNames} 
                 icons={this.state.icons} 
                 fileChosen={this.state.selectedFile}/>); 
       break; 

      default: 
       formStep = (<RegistrationFormStepFour user={this.props.userData} 
                 onChange={this.setUser} 
                 onChangeCheckboxState={this.changeCheckboxState} 
                 onButtonClick={this.onButtonClick} 
                 onButtonPreviousClick={this.onButtonPreviousClick} 
                 errors={this.state.errors}/>); 
     } 

     return (
      <div className="sidebar-menu-container" id="sidebar-menu-container"> 

       <div className="sidebar-menu-push"> 

        <div className="sidebar-menu-overlay"></div> 

        <div className="sidebar-menu-inner"> 
         <div className="contact-form"> 
          <div className="container"> 
           <div className="row"> 
            <div className="col-md-10 col-md-offset-1 col-md-offset-right-1"> 
             {React.cloneElement(formStep, {currentLanguage: languageReg})} 
            </div> 
           </div> 
          </div> 
         </div> 
        </div> 
       </div> 
      </div> 
     ); 
    } 
} 

RegistrationPage.contextTypes = { 
    router: PropTypes.object 
}; 

function mapStateToProps(state, ownProps) { 
    return { 
     userData: state.userRegistrationReducer 
    }; 
} 

function mapDispatchToProps(dispatch) { 
    return { 
     actions: bindActionCreators(actionCreators, dispatch) 
    }; 
} 

export default connect(mapStateToProps, mapDispatchToProps)(RegistrationPage); 

import React from 'react'; 
import Button from '../../common/formElements/button'; 
import RegistrationFormHeader from './registrationFormHeader'; 
import TextInput from '../../common/formElements/textInput'; 
import SelectInput from '../../common/formElements/selectInput'; 

const RegistrationFormStepOne = ({user, onChange, onButtonClick, errors, currentLanguage, countries}) => { 

    const language = currentLanguage; 

    return (
    <div className="contact_form"> 
     <form role="form" action="" method="post" id="contact_form"> 
     <div className="row"> 
      <RegistrationFormHeader activeTab={0} currentLanguage={language}/> 
      <div className="hideOnBigScreens descBox"> 
      <div className="headerTitle">{language.businessInfoConfig}</div> 
      <div className="titleDesc">{language.businessBoxDesc}</div> 
      </div> 
      <div className="col-lg-12"> 
      <h6 className="registrationFormDesc col-lg-10 col-lg-offset-1 col-lg-offset-right-2 col-xs-12"> 
       {language.businessDesc} 
      </h6> 
      <div className="clearfix"></div> 
      <div className="col-sm-6"> 
       <TextInput 
       type="text" 
       name="companyName" 
       label={language.companyNameLabel} 
       labelClass="control-label" 
       placeholder={language.companyNameLabel} 
       className="templateInput" 
       id="company" 
       onChange={onChange} 
       value={user.companyName} 
       errors={errors.companyName} 
       /> 
      </div> 
      <div className="col-sm-6"> 
       <TextInput 
       type="text" 
       name="btwNumber" 
       label={language.vatNumberLabel} 
       placeholder={language.vatNumberLabel} 
       className="templateInput" 
       id="btwNumber" 
       onChange={onChange} 
       value={user.btwNumber} 
       errors={errors.btwNumber} 
       /> 
      </div> 

      <div className="col-sm-12" style={{marginBottom: 25}}> 
       <TextInput 
       type="text" 
       name="address" 
       label={language.addressLabel} 
       placeholder={language.address1Placeholder} 
       className="templateInput" 
       id="address" 
       onChange={onChange} 
       value={user.address} 
       errors={errors.address} 
       /> 
      </div> 

      <div className="col-sm-12" style={{marginBottom: 25}}> 
       <TextInput 
       type="text" 
       name="address1" 
       placeholder={language.address2Placeholder} 
       className="templateInput" 
       id="address" 
       onChange={onChange} 
       value={user.address1} 
       errors="" 
       /> 
      </div> 

      <div className="col-sm-12"> 
       <TextInput 
       type="text" 
       name="address2" 
       placeholder={language.address3Placeholder} 
       className="templateInput" 
       id="address" 
       onChange={onChange} 
       value={user.address2} 
       errors="" 
       /> 
      </div> 

       <div className="col-sm-3"> 
       <SelectInput name="country" 
          label={language.selectCountryLabel} 
          onChange={onChange} 
          options={countries} 
          className="templateInput selectField" 
          defaultOption={language.selectCountry} 
          value={user.country} 
          errors={errors.country} 
          /> 
       </div> 

      <div className="col-sm-3"> 

       <TextInput 
       type="text" 
       name="zipcode" 
       label={language.zipcodeLabel} 
       placeholder={language.zipcodeLabel} 
       className="templateInput" 
       id="zipcode" 
       onChange={onChange} 
       value={user.zipcode} 
       errors={errors.zipcode} 
       /> 
      </div> 
      <div className="col-sm-6"> 
       <TextInput 
       type="text" 
       name="place" 
       label={language.placeLabel} 
       placeholder={language.placeLabel} 
       className="templateInput" 
       id="place" 
       onChange={onChange} 
       value={user.place} 
       errors={errors.place} 
       /> 
      </div> 
      </div> 
      <div className="clearfix"></div> 
      <div className="col-lg-12" style={{marginLeft: 15, marginTop: 30}}> 
      <Button onClick={onButtonClick.bind(this)} 
        name="stepOneNext" 
        value={language.btnNext} 
        icon="arrow-circle-right" 
        style={{margin: '0 auto 60px'}}/> 
      </div> 
     </div> 
     </form> 
    </div> 
); 
}; 

export default RegistrationFormStepOne; 

私はいくつかの簡単な検証を追加しようと、私は私のメインコンポーネントに検証機能を追加しましたが、次のように最初のステップコンポーネントがありますtrueまたはfalseの戻り値がある場合は、ボタンのクリックをチェックします。それが本当なら、ステップステートを適切な値に設定するよりも。最初のステップのフォームフィールドだけを検証しても、次のステップの1つ以上のフォームフィールドを検証しようとすると動作します(今は2番目のステップの最初のフィールドも検証しようとしています)

TextInputコントロールを制御することがtext型の制御不能な入力を変更している。
if(!user.firstName){ 
     formIsValid = false; 
     errors.firstName = languageReg.firstnameEmpty; 
    } 

は私がより

警告を取得します。入力要素は、制御されていない状態から制御された状態に切り替わるべきではありません(またはその逆)。コンポーネントの寿命の間、制御された入力要素または制御されていない入力要素を使用するかどうかを決めます。

検証機能を使用しないと、すべてが完璧に機能します。

アドバイスはありますか?

EDIT

import React, {propTypes} from 'react'; 
import _ from 'lodash'; 

const TextInput = ({errors, style, name, labelClass, label, className, placeholder, id, value, onChange, type}) => { 
    let wrapperClass = "form-group"; 

    if (errors) { 
    wrapperClass += " " + "inputHasError"; 
    } 

    return (
    <div className={wrapperClass} style={style}> 
     <label htmlFor={name} className={labelClass}>{label}</label> 
     <input type={type} 
      className={className} 
      placeholder={placeholder} 
      name={name} 
      id={id} 
      value={value} 
      style={{}} 
      onChange={onChange} 
     /> 
     <div className="errorBox">{errors}</div> 
    </div> 
); 
}; 

TextInput.propTypes = { 
    name: React.PropTypes.string.isRequired, 
    label: React.PropTypes.string, 
    onChange: React.PropTypes.func.isRequired, 
    type: React.PropTypes.string.isRequired, 
    id: React.PropTypes.string, 
    style: React.PropTypes.object, 
    placeholder: React.PropTypes.string, 
    className: React.PropTypes.string, 
    labelClass: React.PropTypes.string, 
    value: React.PropTypes.string, 
    errors: React.PropTypes.string 
}; 

export default TextInput; 

これは、第二段階の構成要素である:警告が存在する理由

import React from 'react'; 
import Button from '../../common/formElements/button'; 
import RegistrationFormHeader from './registrationFormHeader'; 
import TextInput from '../../common/formElements/textInput'; 


const RegistrationFormStepTwo = ({user, onChange, onButtonClick, onButtonPreviousClick, errors, currentLanguage}) => { 
    const language = currentLanguage; 

    return (
     <div className="contact_form"> 
      <form role="form" action="" method="post" id="contact_form"> 
       <div className="row"> 
        <RegistrationFormHeader activeTab={1} currentLanguage={language}/> 
        <div className="hideOnBigScreens descBox"> 
         <div className="headerTitle">{language.personalInfoConfig}</div> 
         <div className="titleDesc">{language.personalBoxDesc}</div> 
        </div> 
        <div className="col-lg-12"> 
         <h6 className="registrationFormDesc col-lg-10 col-lg-offset-1 col-lg-offset-right-2 col-xs-12"> 
          {language.personalDesc} 
         </h6> 
         <div className="col-lg-6 col-md-6 col-sm-6 col-xs-12"> 
          <TextInput 
           type="text" 
           name="firstName" 
           label={language.firsnameLabel} 
           placeholder={language.firsnameLabel} 
           className="templateInput" 
           id="name" 
           onChange={onChange} 
           value={user.firstName} 
           errors={errors.firstName} 
          /> 
         </div> 
         <div className="col-lg-6 col-md-6 col-sm-6 col-xs-12"> 
          <TextInput 
           type="text" 
           name="lastName" 
           label={language.lastnameLabel} 
           placeholder={language.lastnameLabel} 
           className="templateInput" 
           id="name" 
           onChange={onChange} 
           value={user.lastName} 
           errors={errors.lastName} 
          /> 
         </div> 

         <div className="col-lg-6 col-md-6 col-sm-6 col-xs-12"> 
          <TextInput 
           type="text" 
           name="phone" 
           label={language.phoneLabel} 
           placeholder={language.phoneLabel} 
           className="templateInput" 
           id="phone" 
           onChange={onChange} 
           value={user.phone} 
           errors={errors.phone} 

          /> 
         </div> 

         <div className="col-lg-6 col-md-6 col-sm-6 col-xs-12"> 
          <TextInput 
           type="text" 
           name="mobilePhone" 
           label={language.mobileLabel} 
           placeholder={language.mobileLabel} 
           className="templateInput" 
           id="phone" 
           style={{}} 
           onChange={onChange} 
           value={user.mobilePhone} 
           errors={errors.mobilePhone} 
          /> 
         </div> 
         <div className="clearfix"></div> 

         <div className="col-lg-12 col-md-12 col-sm-12 col-xs-12"> 
          <TextInput 
           type="text" 
           name="email" 
           id="email" 
           label={language.emailLabel} 
           placeholder={language.emailLabel} 
           className="templateInput" 
           style={{}} 
           onChange={onChange} 
           value={user.email} 
           errors={errors.email} 
          /> 
         </div> 

         <div className="col-lg-12 col-md-12 col-sm-12 col-xs-12"> 
          <TextInput 
           type="text" 
           name="userName" 
           label={language.usernameLabel} 
           placeholder={language.usernameLabel} 
           className="templateInput" 
           id="name" 
           onChange={onChange} 
           value={user.userName} 
           errors={errors.userName} 
          /> 
         </div> 

         <div className="col-lg-6 col-md-6 col-sm-6 col-xs-12"> 
          <TextInput 
           type="password" 
           name="password" 
           label={language.passwordLabel} 
           placeholder={language.passwordLabel} 
           className="templateInput" 
           id="password" 
           onChange={onChange} 
           value={user.password} 
           errors={errors.password} 
          /> 
         </div> 
         <div className="col-lg-6 col-md-6 col-sm-6 col-xs-12"> 
          <TextInput 
           type="password" 
           name="confirmPassword" 
           label={language.passwordConfirmLabel} 
           placeholder={language.passwordConfirmLabel} 
           className="templateInput" 
           id="password" 
           onChange={onChange} 
           value={user.confirmPassword} 
           errors={errors.confirmPassword} 
          /> 
         </div> 

        </div> 
        <div className="clearfix"></div> 
        <div className="col-lg-6 col-xs-6" style={{marginTop: 30}}> 
         <Button onClick={onButtonPreviousClick} 
           name="btnPrevious" 
           value={language.btnPrevious} 
           icon="arrow-circle-left" 
           style={{marginRight: 10, float: 'right'}}/> 
        </div> 
        <div className="col-lg-6 col-xs-6" style={{marginTop: 30}}> 
         <Button onClick={onButtonClick} name="stepTwoNext" value={language.btnNext} 
           icon="arrow-circle-right" style={{marginLeft: 10, float: 'left'}}/> 
        </div> 
       </div> 
      </form> 
     </div> 

    ); 
}; 

export default RegistrationFormStepTwo; 
+0

TextInputとは何ですか? –

答えて

15

は、これは次のとおりです。値は未定義として指定されている場合、リアクトあなたかどうかを知る方法がありません空の値を持つコンポーネントをレンダリングしたり、コンポーネントを制御しないようにしたい場合に使用します。これはバグの原因です。

値を入力に渡す前に、ヌル/未定義チェックを行うことができます。

a source

+0

しかし、なぜ私は検証機能なしでこの警告を得ていないのですか?検証関数は、フィールド値では何も行いません。 – Boky

+0

@Bokyあなたはレポを提供できますか?あなたはobout "second step"を書きましたが、私はそのコンポーネントを見ませんでした –

+0

これは最初のステップに非常に似ています。私は私の質問を更新しました。 'if(value == null || typeof value ==" undefined ")のようなものを追加した場合{ fieldValue =" "; } else { fieldValue = value; } '私は警告を受けませんが、それは2番目のステップには行かないでしょう。検証機能を削除すると完全に機能します。 – Boky

1

@Kokovinウラジスラフは正しいです。あなたが最初の名前の値が見つからない場合は、それに空の値を与える、ある

<TextInput 
    // your other code 
    value={user.firstName || ''} 
/> 

:コードでこれを置くために、あなたはすべてのあなたの入力value秒でこれを行うことができます。

関連する問題