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にあります。