父组件ParamsForm提交时如何打印子组件Operations表单数据到控制台
实现方案
核心思路用状态提升:把父子组件的表单状态统一收敛到父组件管理,子组件只负责接收状态、触发状态更新的回调,父组件提交的时候直接读取所有状态打印即可,不需要跨组件查找数据,维护成本最低。
改造步骤
1. 父组件 ParamsForm.js 改造
父组件需要完成4件事:
- 存储自身表单字段的状态
- 存储原本放在子组件里的参数列表状态
- 编写表单提交逻辑,触发提交时合并两份数据打印
- 将子组件状态的更新方法通过props传递给子组件
改造后完整代码:
import React, { useState } from 'react' import { Form } from 'react-bootstrap' import styles from '../style.module.css' import Operations from './Operations' const ParamsForm = () => { const [isToggled, setIsToggled] = useState(false) // 父组件自身表单字段状态 const [parentFormData, setParentFormData] = useState({ baseUrl: 'http://localhost:3000/', pathText: '' }) // 提升到父组件管理的子组件参数列表状态 const [operationsParams, setOperationsParams] = useState([{ name: '', type: 'any', description: '' }]) // 表单统一提交逻辑 const handleFormSubmit = (e) => { e.preventDefault() // 合并两份数据打印到控制台 console.log('全量表单数据:', { 父组件字段: parentFormData, 子组件Operations参数: isToggled ? operationsParams : [] }) } return ( <div className={styles.paramFormsContainer}> <Form onSubmit={handleFormSubmit}> <button className={styles.paramFormsBtn} type="button">{parentFormData.baseUrl}</button> <input style={{flex : 1 }} type="text" value={parentFormData.pathText} onChange={(e) => setParentFormData(prev => ({...prev, pathText: e.target.value}))} /> <button type='button' onClick={()=>setIsToggled(!isToggled)} className={styles.pathParamFormsBtn} > Path Params </button> {/* 向子组件传递状态和更新方法 */} {isToggled && ( <Operations paramsList={operationsParams} setParamsList={setOperationsParams} /> )} {/* 补充原代码缺失的提交按钮 */} <button type="submit" className={styles.submitBtn}>提交表单</button> </Form> </div> ) } export default ParamsForm
2. 子组件 Operations.js 改造
子组件不再独立维护参数列表状态,直接使用父组件传入的状态和更新方法,同时修复原代码的几个逻辑问题:
- 删除子组件内部独立定义的
paramsList状态 - 删除子组件内部嵌套的
<form>标签,避免和外层父表单冲突导致提交异常 - 给类型选择下拉框、描述输入框补上受控绑定,原代码这两个字段是不受控状态,无法读取用户输入值
- 给所有非提交按钮加上
type="button",避免点击时误触表单提交
改造后完整代码:
import React, { useState } from 'react' import styles from '../style.module.css' import {FaInfo} from 'react-icons/fa' import ReactTooltip from "react-tooltip"; // 接收父组件传入的状态和更新方法 const Operations = ({ paramsList, setParamsList }) => { const [isToggled, setIsToggled] = useState(true) const handleParamAdd = () =>{ setParamsList([...paramsList, { name: '', type: 'any', description: '' }]) } const handleParamRemove = (index) =>{ const list = [...paramsList] list.splice(index,1) setParamsList(list) } const handleParamsChange = (e, index)=>{ const{name,value} = e.target const list = [...paramsList] list[index][name] = value setParamsList(list) } return ( <div > <div className={styles.operationsBtnContainer}> </div> {isToggled && paramsList.map((singleParam,index)=>( <div key={index} className={styles.pathParamsFormParentContainer}> <div className={styles.pathParamsFormChildContainer}> <input name='name' value={singleParam.name} onChange={(e)=>handleParamsChange(e,index)} placeholder="Name..." style={{flex : 1 }} type="text" /> <select name="type" value={singleParam.type} onChange={(e)=>handleParamsChange(e,index)} > <option value="any">any</option> <option value="string">string</option> <option value="number">number</option> <option value="integer">integer</option> <option value="array">array</option> </select> <input name="description" placeholder="Description..." style={{flex : 1 }} type="text" value={singleParam.description} onChange={(e)=>handleParamsChange(e,index)} /> <button data-tip data-for="requiredTip" type="button"><FaInfo></FaInfo></button> <ReactTooltip id="requiredTip" place="top" effect="float"> required </ReactTooltip> <button type='button' className={styles.addParamsBtn} onClick={handleParamAdd}><span>Add Parameter</span></button> {paramsList.length > 1 && ( <button type='button' className={styles.removeParamsBtn} onClick={()=>handleParamRemove(index)}><span>Remove Parameter</span></button> )} </div> </div> )) } </div> ) } export default Operations
注意事项
- 子组件被切换隐藏时,提交会自动返回空的子组件参数数组,不会读取到隐藏状态下的旧缓存值
- 删除按钮加了数量判断,至少保留1个参数项,避免删空后无法新增参数
- 所有表单字段都改为受控组件,能100%保证读取到最新的用户输入值
内容的提问来源于stack exchange,提问作者nOhAr
相关产品推荐
相关产品推荐

