Reduxフォームに対応したフォーム状態の管理
序章
redux-form は、Reduxを利用したフォームを管理するための優れた方法です。 これは、 react-redux を使用してReactのHTMLフォームがすべての状態を保存するためにReduxを使用することを確認するHigher-Order-Component(HOC)です。
redux-formには、アプリケーションの構築に役立つ次のコンポーネントがあります。
formReducer()
:これは、アプリケーションからの変更に基づいてReduxストアを更新する方法を指示する関数です。 これらの変更は、Reduxアクションによって記述されます。formReducer
は、form
のRedux状態にマウントする必要があります。reduxForm()
:reduxForm()
関数は高階コンポーネントであり、構成オブジェクトを受け取り、常に新しい関数を返します。 これは、フォームコンポーネントをラップし、ユーザーインタラクションをReduxディスパッチアクションにバインドするために使用されます。<Field/>
コンポーネント:ラップされたフォームコンポーネント内に存在するコンポーネント。 フォーム内の入力要素をredux-form logic
に接続する方法として機能します。 言い換えれば、それはユーザーが入力したものから入力を取得する方法です。
redux-form
APIの詳細については、ドキュメントをご覧ください。
このチュートリアルでは、 redux-form を使用して、検証付きのフォームを作成し、Reduxストアに接続します。
前提条件
このチュートリアルを完了するには、次のものが必要です。
- Node.jsのローカル開発環境。 Node.jsをインストールしてローカル開発環境を作成する方法に従ってください
ステップ1-プロジェクトの作成
create-react-appパッケージを使用してReactアプリを構築します。 create-react-app
を使用すると、ビルド構成なしでReactアプリを作成できます。 次のターミナルコマンドを実行すると、create-react-app
を使用できます。 contact-redux
という名前のフォルダーにReactアプリが自動的に作成されます。
npx create-react-app contact-redux
npx
は、5.2以降のバージョンのnpm
でのみ機能することに注意してください。 それより前のバージョンを使用していて、コンピューターでcreate-react-app
を使用したい場合。 以下のターミナルコマンドを実行してcreate-react-app
をインストールし、Reactアプリを起動します。
npm install -g create-react-app create-react-app contact-redux
ディレクトリに移動し、開発サーバーを起動して、すべてが機能することを確認します。 次のコマンドを実行して、新しく作成されたReactアプリを開発モードで起動します。
npm start
ブラウザに次のように表示されます。
これで、Reactアプリが稼働しています。
次のコマンドを実行して、フォームに必要な依存関係を追加します。
npm install --save redux react-redux redux-form
- redux -状態コンテナであり、redux-formが機能するための前提条件です。
- react-redux -React ReduxはReduxの公式Reactバインディングであり、redux-formが機能するための前提条件でもあります
- redux-form-このチュートリアルで使用されているパッケージ。
インストールが完了すると、お問い合わせフォームで作業できます。
ステップ2–フォームの作成
Bulma CDNリンクをindex.html
ファイルに追加して、デフォルトのスタイルを追加します。 public/index.html
ファイルを開き、次のコード行をhead
タグに追加します。
public / index.html
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.6.2/css/bulma.min.css">
src/App.js
ファイルを編集します。 src/App.js
ファイルを開き、ファイルの先頭に以下のコード行を追加します。
src / App.js
import { reduxForm, Field } from 'redux-form';
次に、render()
関数に移動し、次のコードで変更します。
src / App.js
render() { return ( <div className="App"> <header className="App-header"> <img src={logo} className="App-logo" alt="logo" /> <h1 className="App-title">Welcome to React x redux-form</h1> </header> <div className="container"> <p className="App-intro"> Contact Form </p> <SignInForm /> </div> </div> ); }
紹介文が変更され、最も重要なのは、以下で作成する<SignInForm />
コンポーネントを追加したことです。 必要なフォームを返すシンプルなコンポーネントになり、redux-form
コンポーネントに接続されます。 同じsrc/App.js
ファイルで、class App extends Component
の宣言の直前にこのコードを入力します。
src / App.js
let SignInForm = props => { return <form className="form"> <div className="field"> <div className="control"> <label className="label">First Name</label> <Field className="input" name="firstName" component="input" type="text" placeholder="First Name"/> </div> </div> <div className="field"> <div className="control"> <label className="label">Last Name</label> <Field className="input" name="lastName" component="input" type="text" placeholder="Last Name"/> </div> </div> <div className="field"> <div className="control"> <label className="label">Email</label> <Field className="input" name="email" component="input" type="email" placeholder="Email Address"/> </div> </div> <div className="field"> <div className="control"> <label className="label">Proficiency</label> <div className="select"> <Field className="input" name="proficiency" component="select"> <option /> <option value="beginner">Beginner Dev</option> <option value="intermediate">Intermediate Dev</option> <option value="expert">Expert Dev</option> </Field> </div> </div> </div> <div className="field"> <div className="control"> <label className="label">Age</label> <Field className="input" name="age" component="input" type="number" placeholder="Age"/> </div> </div> <div className="field"> <div className="control"> <label className="checkbox"> <Field name="saveDetails" id="saveDetails" component="input" type="checkbox"/> Save Details </label> </div> </div> <div className="field"> <div className="control"> <label className="label">Message</label> <Field className="textarea" name="message" component="textarea" /> </div> </div> <div className="field"> <div className="control"> <button className="button is-link">Submit</button> </div> </div> </form>; };
このコードでは、名、姓、年齢などの情報をユーザーに尋ねる最小限の連絡フォームを設定します。 この形式の興味深いビットは、Field
コンポーネントです。
Field
コンポーネントはredux-form
パッケージに由来し、input
フィールドの記述方法です。 type
小道具は、入力のタイプ、つまり、radio
入力、checkbox
入力、text
入力、またはemail
入力。 component
プロップは、入力フィールドのタイプを決定します。入力フィールドのタイプは、input
、textarea
、select
タグ、およびname
です。 propは、以下で作成するreduxストアのフィールドの状態を識別するために使用されるものです。
したがって、redux-formに接続されたフォームを使用するには、ある種のReduxストアをすでに作成しておく必要があります。これを次に行います。
ステップ3–Reduxストアを設定する
作成したフォームコンポーネント(SignInForm
)を接続できるReduxストアが必要です。 redux
パッケージをインポートすることから始めましょう。 src/index.js
ファイルを開き、基本的にredux
をReactアプリにインポートする次のコード行を追加します。
src / index.js
import { createStore, combineReducers } from 'redux'; import { Provider } from 'react-redux'; import { reducer as formReducer } from 'redux-form';
コードの最初の行は、createStore
とcombineReducers
をインポートします。 createStore は、アプリの完全な状態ツリーを保持するReduxストアを作成するのに役立ち、 combineReducers は、すべてのレデューサー関数を1つのヘルパー関数に管理してから渡すことができます。 createStore
。 これらの関数の詳細については、ReduxAPIリファレンスページをご覧ください。
コードの2行目は、react-redux
からProvider
をインポートします。 Provider
は、ストアの状態をアプリ内のすべてのコンテナーコンポーネントに渡すのに役立ちます。これについては、後で説明します。
コードの3行目は、reducer
をformReducer
としてインポートします。これを使用して、フォームをReduxストアに接続します。
次に、実際のReduxストアを作成し、Provider
コンポーネントを使用して、すべてのコンテナーコンポーネントに適用できることを確認します。 src/index.js
ファイルを次のコードブロックで編集します。
src / index.js
import React from 'react'; import ReactDOM from 'react-dom'; import { createStore, combineReducers } from 'redux'; import { Provider } from 'react-redux'; import { reducer as formReducer } from 'redux-form'; import './index.css'; import App from './App'; import registerServiceWorker from './registerServiceWorker'; const rootReducer = combineReducers({ form: formReducer, }); const store = createStore(rootReducer); ReactDOM.render( <Provider store={store}> <App /> </Provider>, document.getElementById('root') ); registerServiceWorker();
上記のコードブロックでは、combineReducers
関数を使用して、フォームからReduxストアにformReducer
を接続します。 これは基本的に、アクション(この場合はフォームの変更)に応じて状態を更新するために使用されます。 次のコード行は、ReduxのcreateStore
を使用してストアを作成するために使用されます。
この新しく作成されたストアは、App
コンポーネントにラップされたProvider
の助けを借りてアプリのすべての部分で利用できるようになり、store
。
フォームに戻り、最後にストアに接続しましょう。
##ステップ4–フォームをredux-formに接続する
フォームコンポーネントがありますが、まだredux-form
に接続されていません。 それを修正しましょう。 class App extends Component
の直前、およびSignInFormプレゼンテーションコンポーネントの宣言の直後に、このコードブロックを入力します。
src / index.js
SignInForm = reduxForm({ form: 'signIn', })(SignInForm);
上記のコードブロックでは、SignInForm
は、reduxForm
高階コンポーネントを使用してredux接続された形式になっています。 これは、フォームがストアに接続されたことを意味します。 注意すべき点の1つは、構成キーform
です。これは識別子として使用され、フォームコンポーネントの一意の名前を提供するために使用されます。 それらが複数の形式である場合、それらの異なる状態をより適切に管理するために、別々の名前を使用する必要があります。
次に行う必要があるのは、[送信]ボタンをクリックしたときに何が起こるかを構成することです。 理想的なアプリでは、リモートAPIまたは一部のデータベースにデータを送信する必要がありますが、デモンストレーションの目的で、フォームデータをブラウザーコンソールに記録します。 そのためには、小道具からフォームデータを取得し、それらをどこかに保存する必要があります。
SignInForm
コンポーネント内で、return
ステートメントのすぐ上にコード行を追加します。
[label src/index.js] const { handleSubmit } = props; return <form **onSubmit={handleSubmit}** className="form">
SignInForm
形式のprops
は、handleSubmit
に分解されます。 handleSubmit
関数は、送信ボタンがクリックされたときにonSubmit
イベントのハンドラーとしてフォームで使用されます。
最後に、src/App.js
ファイルのApp
コンポーネント内に、フォームデータをブラウザーコンソールに記録する関数を作成します。 render()
関数の直前のファイルに以下のコードブロックを追加します。
src / App.js
handleSignIn = values => { console.log(values); };
次に、handleSignIn
関数をSignInForm
コンポーネントのイベントハンドラーとして追加します。 redux-form
は、フォームから取得したデータを自動的に確認します。これは、上記のhandleSubmit
関数のおかげで、基本的にSignInForm
コンポーネントがコンソールに記録される必要があります。
src / App.js
<SignInForm onSubmit={this.handleSignIn} />
これで、npm start
ターミナルコマンドを実行してアプリを起動できます。 フォームに記入し、[送信]をクリックすると、コンソールに記録された値が表示されます。
ステップ5–検証を追加する
フォームの作成に関しては検証が重要であり、redux-form
にはいくつかの検証機能が付属しており、これから実装します。 src/App.js
ファイルに、以下のコードブロックを入力します。
src / App.js
const validate = val => { const errors = {}; if (!val.firstName) { console.log('First Name is required'); errors.firstName = 'Required'; } if (!val.lastName) { console.log('Last Name is required'); errors.lastName = 'Required'; } if (!val.email) { console.log('email is required'); errors.email = 'Required'; } else if (!/^.+@.+$/i.test(val.email)) { console.log('email is invalid'); errors.email = 'Invalid email address'; } if (!val.age) { errors.age = 'Required' } else if (isNaN(Number(val.age))) { errors.age = 'Must be a number' } else if (Number(val.age) < 18) { errors.age = 'Sorry, you must be at least 18 years old' } return errors; };
validate
関数は、フォームの検証エラーをチェックするために使用されます。 val
パラメーターは、さまざまなフィールドの検証をチェックするために使用されます。 最初に、errors
オブジェクトが空であるかどうかを確認します。空のオブジェクトは、明らかにエラーがないことを意味します。 次に、条件付きロジックを使用して、フィールドが空であるかどうかを確認します。空である場合は、対応するエラーをスローします。 上記のコードブロックでは、firstName
、lastName
、email
、およびage
の検証のみを行っています。 email
検証条件では、空かどうかを確認し、regex
を使用して有効なメールかどうかも確認します。また、age
検証条件では、空かどうかを確認します。数とユーザーが18未満の場合。
次に、検証関数をredux-form
に登録して、検証テストの実行に使用できるようにします。 validate
関数をredux-form
高階コンポーネントに追加します。
src / index.js
SignInForm = reduxForm({ form: 'signIn', validate, })(SignInForm);
検証機能の準備が整い、redux-form
HOCに登録されたので、エラーが発生するたびにエラーを表示し、フォームで新しく作成されたコンポーネントを使用する再利用可能なコンポーネントを作成します。
src / index.js
const renderField = ({ input, label, type, meta: { touched, error, warning } }) => ( <div> <div className="control"> <label className="field">{label}</label> <input className="input" {...input} placeholder={label} type={type}/> {touched && ((error && <span>{error}</span>) || (warning && <span>{warning}</span>))} </div> </div> )
renderField
コンポーネントは、input
オブジェクトの小道具、label
、入力のtype
、およびredux-form
プロパティ。 {touched && ((error && <span>{error}</span>) || (warning && <span>{warning}</span>))}
の行は、フォームフィールドがクリック/フォーカスされたときにエラーがあるかどうかを示すエラーメッセージが表示されることを意味します。 また、エラーが発生した場合、フォームは送信されません。
ここで、フォームをチェックして無効な入力を入力しようとしたり、検証テストのあるフィールドをスキップしたりすると、フォームの下にエラーメッセージが表示されます。
結論
このチュートリアルでは、redux-form
を使用してフォームを作成し、Reduxストアに接続しました。 外部スキーマ検証ツールを必要とせずに、フォームに同期検証を追加しました。
redux-form
の詳細については、公式サイトをご覧ください。また、の例を参照してさらに詳しく調べることができます。
このチュートリアルの完成したコードは、GitHubにあります。