2017-05-25 11 views
2

私たちはフォームで検証を提供するために上位コンポーネントを使用しており、すべての変更イベントに対処する責任があります。私が抱えている問題は、onChangeハンドラをラップされたコンポーネント自体に追加することができないことにあります。そのため、HoCはdivにラップします。我々は実際にはは余分なdivに感謝しないフレックスベースのグリッドシステムを持っています。Reactコンポーネントをルート要素のバブリング変更イベントにリッスンさせることはできますか?

HOCは基本的に次のようになります。

function withValidation(TargetComponent, options = {}) { 

    class ValidatingComponent extends Component { 

     ... 

     render() { 
      return (
       <div 
        ref={(_target) => { this._target = _target; }} 
        onChange={this.onChange} 
       > 
        <TargetComponent 
         {...this.props} 
         {...this.state} 
         onSubmit={this.onSubmit} 
        /> 
       </div> 
      ); 
     } 
    } 

    return ValidatingComponent; 
} 

私が試した最初のものは、単に

render() { 
    return (
     <TargetComponent 
      {...this.props} 
      {...this.state} 
      ref={(_target) => { this._target = _target; }} 
      onChange={this.onChange}   
      onSubmit={this.onSubmit} 
     /> 
    ) 
} 

ラッパーを削除しかし、それはちょうど包まコンポーネントへの小道具としてonChangeを渡すとしました私はそれを手動で呼び出す必要はありません。私は、通常のバニライベントリスナーを取り付けることを試みた。

componentDidMount() { 
    findDOMNode(this._target).addEventListener('change', this.onChange); 
} 

しかし、それはうまくいかなかった。 onChangeは決して誘発されませんでした。私は、それが何か合成的イベントを捕まえていないと推測しています。

Reactコンポーネントが自分自身で変更イベントをリッスンする方法はありますか?私は関連する<input>に到達してそこから呼び出すまで、そのコールバックをコンポーネントツリーの下に通す必要は本当にありません。

私はこの質問がthis oneに似ているように思っていますが、カスタムDOMイベントを扱っています。私はそうではありません。場合

EDIT

私はそれがhereだ、私もバイオリンを作った私がやろうとしているかについて明確にされていませんでした。 <TargetComponent />divでラップされていて、onChangeハンドラがそのdivに接続されている場合、フォームは機能しますが、onChangeがTargetComponent自体の小道具として渡されたばかりです。実際にイベントを聞き、関数を渡すだけではなく、私のHoCに伝えるために何らかの方法が必要です。私はここに入力をラップしていません、私はフォーム全体をラッピングしています。

+0

コンポーネントにイベントハンドラをアタッチする方法を尋ねていますか? 'on'で' onClick'や 'onChange'を実行するとどうなりますか? –

+0

@ Sag1vはい、それは私が求めていることです。高位コンポーネントのラッパーは、プロジェクト全体を通して広範囲にわたって使用され、他のフォームコンポーネントをラップします。もし 'onChange'を直接' 'に添付すると、コードベース全体を 'onChange = {this.props.onChange } 'すべての形式のすべての ''に表示されます。むしろそうする必要はなく、イベントのバブリングに頼る必要があります。 – ivarni

+0

よろしくお願いします.HOCを通すのはどうしたらいいですか? (あなたの例のように) –

答えて

1

もちろん、バブリングを使用することができます。 <TargetComponent />がコンテナとして使用するHTML要素のリスナーをonInputまたはonChangeに設定するだけです。あなたの条件に合格すれば(通常のDOM APIを使用して)イベントターゲットをチェックしてください(おそらく何らかのクラスなどが必要です)に渡したthis.props.onChange()を呼び出してください。しかし、あなたはES6がコールバックとしてfinction矢印使用していない場合は、コールバックにthisをバインドすることを忘れないでください:

<TargetComponent 
    onChange={this.onChange.bind(this)} 
/> 
+1

'render'関数で関数を束縛するのは悪い習慣です。 'bind'はこの' onChange'関数のインスタンスを作成し、これは各 'render'呼び出しで発生します。パフォーマンスが低下する可能性があります。クラスの 'constructor'でそれをバインドする必要があります。 –

+0

これはまさに私がやろうとしていることであり、それはうまくいきません。それは 'onChange'を小道具として渡しますが、それを受け取るコンポーネントはそれをどうするか分かりません。この特定のユースケースで動作しない正確なアプローチの実例については、https://jsfiddle.net/ivarni/69z2wepo/79558/を参照してください。 – ivarni

+0

申し訳ありませんが、おそらく私は自分自身を不明瞭に表現していました。私はあなたの '' ** inner **コンテナに 'onChange'ハンドラを設定すべきであることを意味しました。これはjsfiddleの例の' form'要素です。はい、それぞれの内部コンテナに設定する必要がありますが、少なくとも各入力には設定しないでください。しかし、私は、各入力要素にハンドラを設定することは悪いReactJSの慣習とは思えません。むしろその逆で、私はそれが完全にOKだと思います。 – GProst

1

私はそのようにあなた、formそれを自己にonChangeイベントハンドラをアタッチしても安全だと思いますそれをラップする必要はありません。 a modified version of your jsfiddle

// ... 
render() { 
     const { 
      formData: { 
       age, 
       name, 
      }, 
      onChange 
     } = this.props; 

     return (
      <form onSubmit={this.onSubmit} noValidate={true} onChange={onChange}> 
       <div> 
        <label htmlFor="age">Age</label> 
        <input name="age" value={age} /> 
       </div> 
       <div> 
        <label htmlFor="name">Name</label> 
        <input name="name" value={name} /> 
       </div> 
      </form> 
     ); 
    } 
    // ... 

これは、それはまだあなたが今得ている同じ警告投げても期待どおりに動作します:

警告:失敗したフォームのpropTypeを:あなたはonChangeせずにフォームに フィールドをvalue小道具を提供ハンドラ。これにより、読み取り専用フィールド がレンダリングされます。フィールドを変更可能にする場合は、defaultValueを使用します。それ以外の場合は をonChangeまたはreadOnlyのいずれかに設定します。レンダリング方法が MyFormであることを確認します。

+0

ありがとうございます。それがうまくいく間は、私が望んでいたものではありません。私はここでやろうとしていることはReactでは不可能であると推測しています(抽象も同様です)ので、単純にグリッド要素をラップしないで回避するつもりです。そのハンドラをデイジーチェーンで渡す必要がないのが便利です。私は警告を認識しており、私はそれを扱う方法があります:) – ivarni

関連する問題