web-dev-qa-db-ja.com

Redux-form handleSubmit:ストア状態にアクセスする方法は?

Ajax呼び出しを行うredux-form handleSubmit関数では、AjaxでRedux状態のいくつかのプロパティ(ユーザーIDなど)が必要です。

フォームのコンポーネントでhandleSubmitを定義したい場合、これは十分簡単です。必要なものを渡すためにmapStateToPropsを呼び出すだけで、this.props私のhandleSubmitに。

ただし、優れたReact-Redux開発者のように、別個のビューコンポーネントとコンテナーを書くので、ビューコンポーネントはシンプルで、ほとんどまたはまったく動作しません。したがって、私は私のコンテナでhandleSubmitを定義したい.

繰り返しますが、それを行うためにredux-formがセットアップされています。 onSubmitmapDispatchToPropsを定義すると、フォームはそれを自動的に呼び出します。

ただし、mapDispatchToPropsにはredux状態にアクセスする方法はありません。

さて、問題ありません。必要な小道具をフォームの値とともにhandleSubmitに渡すだけです。

うーん、待って、このメカニズムを使用してhandleSubmitにデータを渡すことは不可能です!パラメーターvaluesを取得しますが、別のパラメーターを追加する方法はありません。

これにより、以下の魅力的な選択肢が残ります(そのうち1と2が機能することを確認できます)。

1 Define a submit handler in the form component, and from there call my own custom submit handler function passed in from mapDispatchToProps. This is okay, but requires my component to know some props from the redux state that aren't required to display the form. (This issue is not unique to redux-form.)

dumbSubmit(values)
{
  const { mySubmitHandler, user} = this.props;
  mySubmitHandler(values, user);
}

<form onSubmit={ handleSubmit(this.dumbSubmit.bind(this)) }>

または、より簡潔に、これをすべて矢印関数に組み合わせることができます。

<form onSubmit={ handleSubmit((values)=>{mySubmitHandler(values, this.props.user);}

次に、このハンドラーを完全に非依存にするために、this.props全体をカスタムハンドラーに戻すだけです。

<form onSubmit={ handleSubmit((values)=>{mySubmitHandler(values, this.props);}

2mapDispatchToPropsではなくmergePropsでonSubmitを定義し、statePropsにアクセスできるようにします。 Dan Abramovは(パフォーマンス上の理由で)mergePropsの使用を推奨していません ですので、これは最適ではないようです。

  function mergeProps(stateProps, dispatchProps, ownProps) {
  const { user } = stateProps.authReducer;
  const { dispatch } = dispatchProps;
  return {
    ...ownProps,
    ...dispatchProps,
    ...stateProps,
     onSubmit: (values) => {
       const { name, description } = values;
       const thing = new Thing(name, description, []);
       dispatch(createNewThing(thing, user.id));
     }
  }

3状態プロパティをredux-formフィールドにコピーします。このフィールドは、フォームコンポーネントの入力コントロールにマップされません。これにより、valuesに返されるhandleSubmitパラメーターでアクセスできるようになります。これは一種のハッキングのようです。

もっと良い方法があるはずです!

もっと良い方法はありますか?

28
stone

この質問を改善するために時間を費やした後、オプション#1は実際にはかなり良い、最後の反復(すべての小道具をカスタムハンドラーに戻す矢印関数)。これにより、コンポーネントはステートレスになり、消費しない状態を完全に無視できます。だから私はそれを合理的な答えと呼ぶつもりです。私はあなたのより良い解決策を聞きたいです!


フォームコンポーネントの矢印関数を使用して送信ハンドラを定義し、そこからmapDispatchToPropsから渡された独自のカスタム送信ハンドラ関数を呼び出します。

<form onSubmit={ handleSubmit((values)=>{mySubmitHandler(values, this.props.user);}

次に、このハンドラーを完全に非依存にするために、this.props全体をカスタムハンドラーに渡します。

<form onSubmit={ handleSubmit((values)=>{mySubmitHandler(values, this.props);}

Submit関数がフォームの一部ではない値と小道具のみを必要とする場合、フォームが使用しない小道具だけを返すことができます。ステートレスコンポーネントでは、これは次のようになります。

const Thing_Create = ({ fields: {name, description}, 
    error, 
    handleSubmit, 
    mySubmitHandler, 
    submitting, 
    onCancel, 
    ...otherprops}) => {
return (
<div>
  <form onSubmit={ handleSubmit((values)=>{
    mySubmitHandler(values, otherprops);}) }>
[rest of form definition would go here]
14
stone

私が見つけた最良の方法は、最初に思いついた解決策に非常に似ています。

Redux-formによって渡されたhandleSubmit propがonSubmit propとして使用される関数を取ることができるという事実を利用し、必要な他のパラメーターを渡すために部分アプリケーションを使用しますonSubmit

アクションクリエーター:

function updateUser(id, { name, lastname }) { ... }

コンポーネントがパラメーターをアクション作成者に直接渡すonUpdateUserプロパティを取得するとします。また、コンポーネントはuserを取得します。これは、フィールドの値とともにアクション作成者に渡すidプロパティを持つオブジェクトです。

成分

<form onSubmit={this.props.handleSubmit(this.props.onUpdateUser.bind(null, this.props.user.id))}>

これは、ステートレスな機能コンポーネントのために簡単に書き直すことができ、アクションクリエーターの左側に配置する限り任意の量のパラメーターで機能し、面倒な作業は必要ありません。ただbind

2
Marco Scabbiolo

thisをバインドすることでこの問題を解決できました。

render()のどこか

<MyCustomFormComponent onSubmit={handleSubmit.bind(this)}/>

handleSumit

  handleSubmit(fields) {
    this.props.onSubmit(fields); //this is properly bound, HURRAY :-)
  }

MapDispatchToProps優れた開発者向け:-)

const mapDispatchToProps = dispatch => ({
  onSubmit: (fields) =>
    dispatch({type: auth.actionTypes.LOGIN, payload: auth.api.login(fields)})
});
1
hhsadiq

これは @ stoneanswer のバリエーションですが、関数プログラミングを使用してオプション1を分解できます。

_const mySubmitHandler = props => values => { /* ...code here */ }

<form onSubmit={ handleSubmit(mySubmitHandler(this.props)) }>
_

この場合、mySubmitHandlerは、_this.props_ですでに閉じている引数を1つだけとる関数を返すため、valuesが渡すhandleSubmit引数を明示的に記述する必要はありません。 。

ramda を使用すると、mySubmitHandlerのカリー化をより適切で読みやすい方法で実行できます。

_import { curry } from 'ramda';

const mySubmitHandler = curry((props, values) => { /* ...code here */ });
_

handleSubmitmySubmitHandlerを構成することで、さらに一歩進めることができます

_import { compose, curry } from 'ramda';

const handleSubmit = values => { /* ...code here */ };
const mySubmitHandler = curry((props, values) => { /* ...code here */ });
const onSubmit = compose(handleSubmit, mySubmitHandler);

<form onSubmit={ onSubmit(this.props) }>
_

onSubmit(this.props)は、1つの引数(values)を取り、_this.props_で閉じた関数を返し、必要なすべてのプロパティにアクセスできる関数を作成することに注意してください!

1
markovchain