検索

ホームページ  >  に質問  >  本文

React の代替サポート ドリル (逆方向、子から親へ) フォームを処理する方法

<p>私は React を初めて使用しており、いくつかの実践的なプロジェクトを通じて学習しています。現在、フォームの処理と検証に取り組んでいます。 SPA で React Router の Form コンポーネントを使用しています。フォーム内には、ラベル入力とエラー メッセージをレンダリングする FormGroup 要素があります。また、FormGroup コンポーネント内で独自の入力コンポーネントを使用して、フォームで使用される入力のロジックと状態管理を分離します。 </p> <p>そこで、次のようにサンプル ログイン ページに Form コンポーネントと FormGroup コンポーネントを配置しました。 </p> <p><em>pages/Login.js</em></p> <pre class="brush:js;toolbar:false;">import { useState } from 'react'; import { Link, Form, useNavigate, useSubmit } from 'react-router-dom'; FormGroup を '../components/UI/FormGroup' からインポートします。 '../components/UI/Button' からボタンをインポートします。 カードを「../components/UI/Card」からインポートします。 インポート './Login.scss'; 関数 LoginPage() { const navigate = useNavigate(); const submit = useSubmit(); const [isLoginValid, setIsLoginValid] = useState(false); const [isPasswordValid, setIsPasswordValid] = useState(false); varresetLoginInput = null; varresetPasswordInput = null; isFormValid = false; if(isLoginValid && isPasswordValid) { isFormValid = true; } 関数 formSubmitHandler(event) { イベント.preventDefault(); if(!isFormValid) { 戻る; } リセットログイン入力(); リセットパスワード入力(); submit(event.currentTarget); } 関数loginValidityChangeHandler(isValid) { setIsLoginValid(isValid); } 関数passwordValidityChangeHandler(isValid) { setIsPasswordValid(isValid); } 関数resetLoginInputHandler(reset) { リセットログイン入力 = リセット; } 関数resetPasswordInputHandler(reset) { リセットパスワード入力 = リセット; } 関数 switchToSignupHandler() { ナビゲート('/サインアップ'); } 戻る ( <div className="ログイン"> <div className="login__logo"> 囲碁カップ </div> <p className="login__description"> Go Cup アカウントにログインします </p> <カード枠> <フォーム onSubmit={formSubmitHandler}> <フォームグループ id="ログイン" label="ユーザー名または電子メール アドレス" inputProps={{ タイプ: "テキスト"、 名前: 「ログイン」、 有効性: (値) => { 値 = 値.trim(); if(!値) { return [false, 'ユーザー名または電子メール アドレスが必要です。'] } else if(値.長さ < 3 || 値.長さ > 30) { return [false, 'ユーザー名または電子メール アドレスは少なくとも 3 文字、最大 30 文字である必要があります']; } それ以外 { 戻り値 [true、null]; } }、 onValidityChange:loginValidityChangeHandler、 onReset:resetLoginInputHandler }} /> <フォームグループ id="パスワード" ラベル=「パスワード」 サイドラベル要素={ <リンク先="/password-reset"> パスワードをお忘れですか? </リンク> } inputProps={{ タイプ: 「パスワード」、 名前: "パスワード"、 有効性: (値) => { 値 = 値.trim(); if(!値) { return [false, 'パスワードが必要です。'] } else if(値.長さ < 4 || 値.長さ > 1024) { return [false, 'パスワードは 4 文字以上、最大 1024 文字でなければなりません。']; } それ以外 { 戻り値 [true、null]; } }、 onValidityChange:passwordValidityChangeHandler、 onReset:resetPasswordInputHandler }}/> <div className="text-center"> <ボタンクラス名="w-100" type="送信"> ログイン </ボタン> <span className="login__or"> または </span> <ボタンクラス名="w-100" onClick={switchToSignupHandler}> サインアップ </ボタン> </div> </フォーム> </カード> </div> ); } デフォルトのログインページをエクスポートします。 </pre> <p>上記のコードでわかるように、FormGroup コンポーネントを使用し、<code>onValidityChange</code> プロパティと <code>onReset</code> プロパティを渡して <code>isValid</ を取得します。 code> value の更新された値。フォーム送信後の入力をリセットする機能の変更・リセット機能等カスタム フック useInput を使用して、入力コンポーネントに <code>isValid</code> 関数と <code>reset</code> 関数を作成します。値が変更されたときに isValid 値を渡し、FormGroup コンポーネントで定義された props を使用して入力コンポーネントからリセット関数を渡します。また、ログイン ページで <code>isLoginValid</code> および <code>isPasswordValid</code> 状態定義を使用して、子の入力から渡された更新された <code>isValid</code> 状態値を保存しています。成分。そこで、入力コンポーネントで状態を定義し、props を使用してそれらを親コンポーネントに渡し、その値をその親コン​​ポーネントで作成された他の状態に保存しました。進行中の支柱の穴あけ作業は少し不快な気分になりました。 </p> <p>状態は入力コンポーネント内で管理されます。次の状態があります: </p>
P粉419164700P粉419164700457日前570

全員に返信(2)返信します

  • P粉627136450

    P粉6271364502023-09-02 15:06:02

    React の状態管理については、制御された状態と制御されていない状態の 2 つの主な考え方があります。制御されたフォームは、どこからでも値にアクセスして反応性を提供できる React コンテキストを使用して制御できます。ただし、制御された入力は、特に各入力でフォーム全体を更新する場合にパフォーマンスの問題を引き起こす可能性があります。ここで、制御されていない形式が登場します。このパラダイムでは、すべての状態管理でブラウザのネイティブ機能を利用して状態を表示する必要があります。このアプローチの主な問題は、フォームの React の側面が失われ、送信時にフォーム データを手動で収集する必要があり、そのための複数の参照を維持するのが面倒になる可能性があることです。

    制御された入力は次のようになります:

    リーリー

    EDIT: @Arkellys が指摘したように、フォーム データを収集するために参照は必ずしも必要ありません。これは FormData

    を使用した例です。

    そして制御不能:

    リーリー

    これら 2 つの例から、どちらの方法を使用しても複数コンポーネントのフォームを維持するのは面倒であることが明らかであるため、フォームの管理を支援するためにライブラリがよく使用されます。私は個人的に React Hook Form を、十分にテストされ、メンテナンスが行き届いた、使いやすいフォーム ライブラリとして推奨します。最適なパフォーマンスを実現するために制御されていない形式を採用しながらも、単一の入力を監視してリアクティブ レンダリングを行うことができます。

    Redux、React コンテキスト、またはその他の状態管理システムのいずれを使用するかについては、正しく実装されていると仮定すると、パフォーマンスの点で通常は違いはありません。 flux アーキテクチャ が好きなら、ぜひ Redux を使用してください。ただし、ほとんどの場合、React コンテキストはパフォーマンスが高く、十分です。

    あなたの useInput カスタム フックは、問題を解決しようとする勇敢だが見当違いの試みのように見えます react-hook-form および react-final-form コード > すでに解決されています。この抽象化により、不必要な複雑さと予測不可能な 副作用が生じます。さらに、ミラー小道具 これは、React ではアンチパターンであることがよくあります。

    独自のフォーム ロジックを本当に実装したい場合 (教育目的でない限り、実装しないことをお勧めします)、次のガイドラインに従うことができます。

      真実の情報源を最も共通の祖先に保つ
    1. 状態のミラーリングとコピーを避ける
    2. useMemo
    3. useRef を使用して、再レンダリングを最小限に抑えます

      返事
      0
  • P粉596191963

    P粉5961919632023-09-02 11:36:55

    これは、Redux のようなパブリッシュ/サブスクライブ ライブラリを使用するか、コンポーネント ツリーを通じて状態を伝播するかを決定するために使用する簡単な側面です。

    2 つのコンポーネントに親子関係があり、互いに最大 2 エッジ離れている場合、子の状態を親に伝播します

    親 -> 子 1 レベル 1 -> 子 1 レベル 2 ------ OK

    親 -> 子1-レベル1 ------ OK

    親 -> 子 1 レベル 1 -> 子 1 レベル 2 -> 子 1 レベル 3 --> ステータスを子 1 レベル 3 から親に変更するにはトリップが多すぎます

    • インタラクティブコンポーネント間の距離が 2 エッジを超える場合は、redux を使用してください
    • 兄弟コンポーネント、つまり親コンポーネントを共有し、相互に通信する必要があるサブコンポーネントには redux を使用します (サイド パネルでツリー項目を選択し、メイン コンポーネントで選択した項目の詳細を表示します)

    導入以来

    • useInput は過剰なリファクタリングであることがわかりました。入力コンポーネントは、入力関連の操作、より優れた抽象検証などを管理するのに十分である必要があります。
    • フォーム送信時にすべての検証をトリガーできます。その場合、制御された入力は必要ありません (フォームの onSubmit イベントに検証を追加します)
    • ただし、フォームに含まれるフィールドが多すぎて (たとえば、5 つ以上)、送信する前にフィールドを検証したい場合は、入力フィールドの onBlur イベントを使用するか、デバウンス アクション (デバウンス フロムなど) で onInput を使用できます。 lodash 操作) または次のように実装します

    リーリー

    返事
    0
  • キャンセル返事