Ajax呼び出しを行うredux-form handleSubmit
関数では、AjaxでRedux状態のいくつかのプロパティ(ユーザーIDなど)が必要です。
フォームのコンポーネントでhandleSubmit
を定義したい場合、これは十分簡単です。必要なものを渡すためにmapStateToProps
を呼び出すだけで、this.props
私のhandleSubmit
に。
ただし、優れたReact-Redux開発者のように、別個のビューコンポーネントとコンテナーを書くので、ビューコンポーネントはシンプルで、ほとんどまたはまったく動作しません。したがって、私は私のコンテナでhandleSubmitを定義したい.
繰り返しますが、それを行うためにredux-formがセットアップされています。 onSubmit
でmapDispatchToProps
を定義すると、フォームはそれを自動的に呼び出します。
ただし、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
パラメーターでアクセスできるようになります。これは一種のハッキングのようです。
もっと良い方法はありますか?
この質問を改善するために時間を費やした後、オプション#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]
私が見つけた最良の方法は、最初に思いついた解決策に非常に似ています。
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
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)})
});
これは @ stone の answer のバリエーションですが、関数プログラミングを使用してオプション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 */ });
_
handleSubmit
とmySubmitHandler
を構成することで、さらに一歩進めることができます
_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
_で閉じた関数を返し、必要なすべてのプロパティにアクセスできる関数を作成することに注意してください!