以前、動的フォームを記述しているときに落とし穴に遭遇しました。インデックスの添え字をキーとして使用するとバグが発生し、非常に深刻になります。 今日は記録のために記事を書く時間があります。対処方法とロジック 私は antd3 バージョンを使用しています。3 と 4 のフォームは少し異なりますが、違いはそれほど大きくないはずです。 必要: 1. 切り替えるタイプを選択し、固定テンプレートを表示する 2. 新しいフィールドを追加することで、フォームの各行を動的に増減できます。 3. 各行のフィールドに入力する必要があるかどうかを制御する 4. 編集時のパラメータのバックフィル 効果画像: いくつかのキーコード: React をインポートします。{ コンポーネント } から 'react' をインポートします。 './index.less' からスタイルをインポートします。 輸入 { テーブル、 ボタン、 選択、 ポップコンファーム、 モーダル、 形状、 入力、 無線、 行、 列、ツールチップ、 アイコン、 メッセージ、 ページネーション、入力番号、 } 'antd' から; const Option = Select.Option; FormItem は Form.Item に代入されます。 id = 0 とします。 @フォームを作成します() クラス Index は Component を拡張します { マーケットID = 0; 状態 = { 選択タイプ: '' orderType: 1, //記事 1 マップ 2 タイプロード: false、 isEdit: false、 見た目: 偽、 表示: 偽、 ページサイズ: 10, ページ番号: 1, キーワード: ''、 行: {}、 タイプリスト: {}, モック: {}, マップタイプ: [{ 'フィールド名': '名前', 'isImg': 0, '順序': 0, '備考': '名前', }, { 'フィールド名': 'ラベル', 'isImg': 0, '順序': 0, '備考': 'ラベル', }, { 'フィールド名': 'lon', 'isImg': 0, '順序': 0, '備考': '経度', }, { 'フィールド名': 'lat', 'isImg': 0, '順序': 0, '備考': '緯度', }], 記事タイプ: [{ 'フィールド名': '名前', 'isImg': 0, '順序': 0, '備考': '名前', }, { 'フィールド名': 'ラベル', 'isImg': 0, '順序': 0, '備考': 'ラベル', }], }; /** * 動的テーブル値に必要なデータ形式を生成します * @param values * @returns {[]} */ createValues = (値) => { 定数行 = this.state; 定数データ = []; const newValues = { // 送信されたデータを格納するために新しいオブジェクトを使用します...値、 }; const fieldNameData = []; // fieldName 値を保存 const commentsData = []; // comments 値を保存 const isImgData = []; // isImg 値を保存 const orderData = []; // orderData 値を保存 const fieldName = RegExp(/fieldName/); const 注釈 = RegExp(/注釈/); 定数isImg = RegExp(/isImg/); for (constキーin newValues) { if (フィールド名.テスト(キー)) { フィールド名データ.push(newValues[キー]); } } for (constキーin newValues) { if (remarks.test(key)) { 注釈Data.push(newValues[key]); } } for (constキーin newValues) { if (isImg.test(キー)) { isImgData.push(newValues[キー]); } } for (constキーin newValues) { if (isImg.test(キー)) { orderData.push(newValues[キー]); } } フィールド名データ.forEach((アイテム、インデックス) => { データ.push({ フィールド名: アイテム、 備考: 備考データ[インデックス], isImg: isImgData[インデックス], 順序: orderData[インデックス], id: row.dataType ? row.dataType.id: ''、 }); }); データを返します。 }; ハンドルOk = e => { this.props.form.validateFields((err, 値) => { もしエラーが起きたら 定数 row, isEdit } = this.state; 定数パラメータ = { データ型: { 名前: 値.名前、 タイプ: 値.type、 id: row.dataType ? row.dataType.id: ''、 }, タイプフィールド: [], }; パラメータ typeFields = this.createValues(値); if (isEdit) { editType(params).then(res => { (res.code === 0)の場合{ message.info('変更に成功しました'); this.setState({ 表示: 偽、 isEdit: false、 }); this.fetchTypeList(); this.props.form.resetFields(); } }); } それ以外 { addType(params).then(res => { (res.code === 0)の場合{ message.info('正常に追加されました'); this.setState({ 表示: 偽、 isEdit: false、 }); this.fetchTypeList(); this.props.form.resetFields(); } }); } } }); }; lookOrEditTypeModal = (フラグ、レコード) => { const { articleType, mapType } = this.state; if (flag === 'add') { //デフォルトの記事テンプレートを追加します this.marketId = articleType.length + 1; //動的キータグの長さを設定します this.setState({ 表示: true、 行: { typeFields: articleType }, }); } それ以外の場合 (フラグ === '編集') { this.setState({ 表示: true、 }); getType({ dataTypeId: record.id }).then(res => { (res.code === 0)の場合{ this.marketId = res.data.typeFields.length + 1; // 動的キータグの長さを設定する this.setState({ 行: res.data、 isEdit: フラグ === 'edit'、 }); } }); } それ以外 { this.setState({ 見た目: true、 }); getType({ dataTypeId: record.id }).then(res => { (res.code === 0)の場合{ this.setState({ 行: res.data、 }); } }); } }; onChangeType = (値) => { const { フォーム } = this.props; const { orderType、 row、 articleType、 mapType } = this.state; this.props.form.resetFields(); 定数パラメータ = {}; if (value === 1) { // 記事タイプ params['typeFields'] = articleType; this.marketId = articleType.length + 1; } それ以外 { パラメータ['typeFields'] = mapType; this.marketId = mapType.length + 1; } this.setState({ 行: パラメータ、 注文タイプ: 値、 }); }; //メソッドを削除します! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! 削除ファイル = k => { const { フォーム } = this.props; const keys = form.getFieldValue('keys'); キーの長さが1の場合 戻る; } フォーム.setFieldsValue({ キー: keys.filter(key => key !== k), }); }; // メソッドを追加します! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ファイルを追加 = () => { const { フォーム } = this.props; const keys = form.getFieldValue('keys'); const nextKeys = keys.concat(this.marketId++); フォーム.setFieldsValue({ キー: nextKeys、 }); }; judgeIsTemplet = (データ) => { if (!データ) { false を返します。 } if ((data.fieldName === 'lat') || (data.fieldName === 'lon') || (data.fieldName === 'label') || (data.fieldName === 'name')) { true を返します。 } }; handleValidator = (ルール、値、コールバック) => { もし(!val) { 折り返し電話(); } 検証結果 = /^[5A-Za-z0-9-\_]+$/.test(val); 結果が検証された場合 callback('正しいテーブルフィールドを入力してください'); } 折り返し電話(); }; 列 = [ { タイトル: 'タイプ名'、 データインデックス: '名前', キー: '名前'、 幅: 500, }, { タイトル: 「タイプ」、 データインデックス: 'type', キー: 'type'、 レンダリング: (テキスト) => { 戻り値 text === 1 ? '記事' : 'マップ'; }, }, { タイトル: 「オペレーション」 データインデックス: 'アドレス', キー: 'アドレス'、 レンダリング: (テキスト、レコード) => { <div> を返す <Button type='link' onClick={() => this.lookOrEditTypeModal('look', record)}>表示</Button> <Button type='link' onClick={() => this.lookOrEditTypeModal('edit', record)}>編集</Button> <Popconfirm title="削除を確認しますか?" onConfirm={() => this.deleteTypeClick(record)}> <Button type='link'>削除</Button> </ポップ確認> </div>; }, }, ]; 与える() { const { selectType、typeLoading、mock、row、isEdit、typeList、keyWord、lookVisible } = this.state; const { getFieldDecorator、getFieldValue } = this.props.form; typeFields を row.typeFields || [] とします。 定数 initData = []; typeFields.forEach((item, index) =>{//実際のデータに応じてデフォルトのキー配列を設定します。initData.push(index); }); getFieldDecorator('keys', { initialValue: initData }); //フォームにキー フィールドを追加し、デフォルト値を設定します。これにより、編集時に編集とバックフィルの効果が生成されます。 const キー = getFieldValue('キー'); const formItems = keys.map((k) => ( <行ガター={12} キー={k} クラス名={styles.form_row}> <FormItem ラベル="フィールド" キー={`fieldName_${k}`}> {getFieldDecorator(`fieldName_${k}`, { 初期値: row.typeFields[k] ? row.typeFields[k].fieldName : ''、 validateTrigger: ['onChange', 'onBlur'], //子ノードの値のタイミングをチェックするrules: [{ 必須: true、 メッセージ: '英語のフィールドを入力してください!', }, { バリデータ: this.handleValidator、 }], })(<Input placeholder="英語のフィールドを入力してください" max={30} disabled={this.judgeIsTemplet(row.typeFields[k])}/>)} </フォーム項目> <FormItem label="名前" key={`remarks_${k}`}> {getFieldDecorator(`remarks_${k}`, { 初期値: row.typeFields[k] ? row.typeFields[k].remarks: ''、 検証トリガー: ['onChange', 'onBlur'], ルール: [{ 必須: true、 メッセージ: '中国語の名前を入力してください!', }], })(<Input placeholder="中国語名を入力してください" disabled={this.judgeIsTemplet(row.typeFields[k])}/>)} </フォーム項目> <FormItem label="Sort" key={`order_${k}`}> {getFieldDecorator(`order_${k}`, { 初期値: row.typeFields[k] ? row.typeFields[k].order : 0, })(<InputNumber style={{width:75}} placeholder="Sort" />)} </フォーム項目> <FormItem label="画像" キー={k}> {getFieldDecorator(`isImg_${k}`, { 初期値: row.typeFields[k] ? row.typeFields[k].isImg: 0, ルール: [{ 必須: true、 }], })(<Radio.Group が無効 = {this.judgeIsTemplet(row.typeFields[k])}> <ラジオ値={0}>いいえ</ラジオ> <ラジオ値={1}>はい</ラジオ> </ラジオグループ>)} </フォーム項目> {!this.judgeIsTemplet(row.typeFields[k]) ? ( <Icon type="minus-circle" onClick={() => this.removeFile(k)} title='削除'/> ) : ヌル} </行> )); 戻る ( <div className={styles.wrap_type}> <モーダル title="タイプ管理" 可視 = {この状態が可視} onOk={this.handleOk} onCancel = {this.handleCancel} 幅={890} // クラス名={styles.modal_type} マスククローズ可能={false} > <フォームレイアウト='インライン'> <行スタイル={{ textAlign: 'center', marginBottom: 14 }}> <FormItem label="タイプを選択"> {getFieldDecorator('type', { 初期値: row.dataType ? row.dataType.type : 1, ルール: [{ 必須: true、 }], })(<onChange={this.onChangeType}、disabled={isEdit}、style={{ width: 200 }}> を選択します。 <オプション値={1}>記事の種類</オプション> <オプション値={2}>マップタイプ</オプション> <オプション値={3} 無効={true}>ファイルタイプ</オプション> </選択>)} </フォーム項目> <FormItem label="タイプ名"> {getFieldDecorator('名前', { 初期値: row.dataType ? row.dataType.name : ''、 ルール: [{ 必須: true、 メッセージ: 'タイプ名を入力してください!', }], })(<Input placeholder="タイプ名を入力してください" style={{ width: 200 }}/>)} </フォーム項目> </行> {フォーム項目} <div style={{ margin: 'auto', textAlign: 'center' }}> <Button icon="plus" onClick={this.addFile} style={{ marginTop: 10 }}>新しいフィールドを追加</Button> </div> </フォーム> </モーダル> </div> ); } } デフォルトのインデックスをエクスポートします。 重要な点は、marketID を動的に追加されたキーとして設定し、その値を動的キーとして使用することです。 (配列の添え字インデックスをキーとして使用しないでください)。 これで、React antd でフォームを動的に増減する方法についての記事は終了です。React antd でフォームを動的に増減する方法についての詳細は、123WORDPRESS.COM の過去の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。 以下もご興味があるかもしれません:
|
>>: MySQL デッドロックのトラブルシューティングの全プロセス記録
序文しばらく前にMysqlのデッドロック問題に遭遇したので、解決しました。問題の説明: Mysql ...
目次概要1. コンポジションAPI 1. ref と reactive の違いは何ですか? 2. 周...
目次ノードのバージョンが一致しない、ノードをアップグレードまたはダウングレードするnvm を使用して...
目次JavaScriptでは、 forループを記述する一般的な方法がいくつかあります。最初の、そして...
目次1. プロジェクトの見通し2. 知識ポイントObject.assign() の使用法filter...
目次ネイティブJS GETリクエストの送信方法投稿リクエストの送信方法パラメータ付きのGETリクエス...
最近、ウェブサイトを開発する際にトップに戻るボタンを作成する必要がありますが、私は主にバックエンドの...
この記事では、アコーディオン効果を実現するためのJavaScriptの具体的なコードを参考までに紹介...
目次JavaScriptでは、通常、次のコードのようにクラスを簡単に定義できます。 var サンプル...
Docker の導入規模が大きくなると、コンテナを監視する必要があります。一般的に、Docker に...
MySQL 5.7.21 winx64無料インストールバージョンの設定方法、参考までに、具体的な内容...
目次序文1. 需要と効果必要効果2. コードの実装index.vue(html)日付方法テスト結果3...
ソケットオプション機能機能: ソケットファイル記述子の属性の読み取りと設定に使用されるメソッド #i...
CUDA インストール cuda をダウンロードサポートされているcudaバージョンを表示するには...
注: 親コンテナーに高さと :data='Array' および overfolw:h...