2017-05-18 7 views
-1

学習目的のために、私はReactJSのウィザードを使って小さなアプリを書いています。ReactJSシンプルフォームウィザード

次のようにウィザードのコンポーネントをいくつか作成しました。

  • プログレス
  • ウィザード
    • WizardStepOne
    • WizardStepOneForm
    • WizardStepTwo
    • WizardStepTwoForm

ウィザードコンポーネントでは、プログレッションを表示するためのPorgressBarコンポーネントを含めて、各 'StepForm'に含まれるボタンのoneClick値を決定し、値を取得して次の 'WizardStepTwoForm'コンポーネントを表示するswitch文を作成しました。

これはすべて正常に動作し、まさに私が期待していることですが、私は1つの問題に直面しています。私は 'WizardStepOneForm'を検証する前に、ユーザーが次の 'WizardStepTwoForm'フォームを取得できないようにしたいと思います。そこで、ユーザーが次の状態にクリックできるかどうかを判断するために、親コンポーネントに状態を返す方法があります。または、検証が完了するまでボタンを無効にしますが、この場合、ユーザーはフォームの検証のためにボタンをクリックすることができません。

私はAPIにデータを送信したいフォームを送信している間、ディスパッチは機能していますが、私はちょうどそれを正しく動作させるために私は親(ウィザード)のswitch文がフォームは有効です。

ウィザード

//.. imports 

class Wizard extends React.Component { 

    constructor(props) { 
     super(props); 
     this.state = { 
      step : 'stepOne', 
      progression : '0%' 
     }; 

     this.handleFormSubmit = this.handleFormSubmit.bind(this); 
    } 

    componentDidMount() { 
     const wizard = JSON.parse(localStorage.getItem('wizard')); 
     if (wizard !== null) { 
      this.setState({ 
       step: wizard.step, 
       progression: wizard.progression 
      }); 
     } 
    } 

    componentDidUpdate() { 
     localStorage.setItem('wizard', JSON.stringify({ 
      step  : this.state.step, 
      progression : this.state.progression 
     })); 
    } 

    handleFormSubmit(e) { 

     switch (e.target.value) { 
      case 'stepOne' : 
       this.setState({ 
        step : 'stepOne', 
        progression : '0%', 
       }); 
       break; 
      case 'stepTwo' : 
       this.setState({ 
        step : 'stepTwo', 
        progression : '50%' 
       }); 
       break; 
     } 
    } 

    /** 
    * 
    * Render 
    * @return {JSX} 
    */ 
    render() { 

     const { step, progression } = this.state; 

     switch (step) { 
      case 'stepOne' : 
       return (
        <div> 
         <Header /> 

          <WizardProgressBar progression={progression} stepOne="active" stepTwo="" /> 

          <WizardStepOne handleFormSubmit={this.handleFormSubmit} /> 

         <Footer/> 
        </div> 
       ); 
       break; 
      case 'stepTwo' : 
       return (
        <div> 
         <Header /> 

          <WizardProgressBar progression={progression} stepOne="done" stepTwo="active" /> 

          <WizardStepTwo handleFormSubmit={this.handleFormSubmit} /> 

         <Footer/> 
        </div> 
       ); 
       break; 
     } 
    } 
} 

export default Wizard; 

WizardStepOne

export default class WizardStepOne extends React.Component { 

constructor(props) { 
    super(props); 
} 

/** 
* 
* Render 
* @return {XML} 
*/ 
render() { 

    return(
     <div className="step-one"> 

      <h1>Step 1</h1> 

      <WizardStepOneForm handleFormSubmit={this.props.handleFormSubmit} /> 

     </div> 
    ); 
} 

}

WizardStepForm

//... imports 

@connect((store) => { 
    return { 

    }; 
}) 

export default class WizardStepOneForm extends React.Component { 

    constructor(props) { 
     super(props); 
     this.state = { 
      formData : { 
       firstName : '', 
       lastName : '', 
      }, 
      formErrors : { 
       firstName : true, 
       lastName : true, 
      }, 
      formErrorMessages : { 
       firstName : 'some validation message', 
       lastName : 'some validation message', 
      }, 
      formButtonEnabled : true, 
     } 

     this.handleSubmit   = this.handleSubmit.bind(this); 
     this.handleFirstNameChange = this.handleFirstNameChange.bind(this); 
     this.handleLastNameChange = this.handleLastNameChange.bind(this); 
    } 

    componentDidMount() { 
     const stepOne = JSON.parse(localStorage.getItem('stepOne')); 
     if (stepOne !== null) { 
      this.setState({ 
       formData : stepOne.formData, 
       formErrors : stepOne.formErrors, 
       formErrorMessages : stepOne.formErrorMessages, 
      }); 
     } 
    } 

    handleFirstNameChange(e) { 

     let formData   = this.state.formData; 
     let formErrors  = this.state.formErrors; 
     let formErrorMessages = this.state.formErrorMessages; 

     formData.firstName = e.target.value; 

     if (!e.target.value) { 
      formErrors.firstName = true; 
     } else { 
      formErrors.firstName = false; 
     } 
     this.setState({ formData : formData, formErrors : formErrors, formErrorMessages : formErrorMessages }); 
     localStorage.setItem('stepOne', JSON.stringify({ formData : formData, formErrors : formErrors, formErrorMessages : formErrorMessages })); 
    } 

    handleLastNameChange(e) { 

     let formData   = this.state.formData; 
     let formErrors  = this.state.formErrors; 
     let formErrorMessages = this.state.formErrorMessages; 

     formData.lastName  = e.target.value; 

     if (!e.target.value) { 
      formErrors.lastName = true; 
     } else { 
      formErrors.lastName = false; 
     } 
     this.setState({ formData : formData, formErrors : formErrors, formErrorMessages : formErrorMessages }); 
     localStorage.setItem('stepOne', JSON.stringify({ formData : formData, formErrors : formErrors, formErrorMessages : formErrorMessages })); 
    } 

    handleSubmitButton() { 

    } 

    handleSubmit(e) { 

     e.preventDefault(); 

     this.props.dispatch(addUser(this.state.formData)); 
    } 

    /** 
    * 
    * Render 
    * @return {XML} 
    */ 
    render() { 

     const firstNameError = this.state.formErrors.firstName ? 'error' : ''; 
     const lastNameError = this.state.formErrors.lastName ? 'error' : ''; 

     return(
      <form className="step-one-form"> 

       <div className="form-group right"> 

        <div className="form-group__form-row"> 

         <p className={classnames('col-2', firstNameError)}> 
          <label htmlFor="first_name">First name:</label> 
          <input type="text" id="firstName" name="fist_name" autoComplete="off" onChange={this.handleFirstNameChange} value={this.state.formData.firstName} /> 
          { firstNameError ? <FormElementErrorMessage message={this.state.formErrorMessages.firstName} /> : '' } 
         </p> 

         <p className={classnames('col-2', lastNameError)}> 
          <label htmlFor="last_name">Last name:</label> 
          <input type="text" id="lastName" name="last_name" autoComplete="off" onChange={this.handleLastNameChange} value={this.state.formData.lastName} /> 
          { lastNameError ? <FormElementErrorMessage message={this.state.formErrorMessages.lastName} /> : '' } 
         </p> 

        </div> 

       </div> 

       <button disabled={this.state.formButtonEnabled} onClick={this.props.handleFormSubmit} value="stepTwo">Next step</button> 

      </form> 
     ); 
    } 
} 
+0

あなたはreact-albus https://github.com/americanexpress/react-albusを見ましたか? –

+0

私が見る限り、WizardStepOneFormコンポーネントでフォームの検証が行われるのと同じ問題が残ります – directory

答えて

0

だから、思ったよりおそらくもっと簡単だと分かった。

フォーム送信ハンドラは、フォームが作成された子コンポーネントにあります。だから私たちはそれを親から支柱として下方に押し出す必要はありません。

フォーム 'stepOne'が有効なときにディスパッチャ経由でアクションを開始するので、私たちはレデューサーによって与えられた状態を変更します。ストアはこの状態の変更を受け取り、これは接続経由で追加され、アプリケーションのルートにプロバイダがあり、親コンポーネントはこの状態変更を受け取り、次のウィザード画面を起動することができます。