React嵌套动态表单新增父表单项时子表单自动加载如何解决
问题根因
你当前的两级嵌套表单共用了全局的bookvideoc状态存储所有子视频项,所有渲染出来的主视频表单项都会读取同一个子视频列表渲染,所以新增主视频项时,自然会把当前全局存储的子视频全部显示出来。另外你代码中还有输入框值绑定错误的问题,所有主项的输入会共享同一个值。
修复步骤
1. 调整主视频模板结构
给每个主视频项新增独立的children字段存储自己的子视频列表,避免全局共享:
const videoTemplet = { book_All_details: "", number_of_chapters:"", chapter:'', video_title: "", description: "", video_url: "", video_image: "", // 新增子视频专属字段,每个主项独立持有子列表 children: [] } const [bookvideo ,setBookvideo] = useState([videoTemplet]);
2. 删除全局子视频相关状态,替换为父子关联的操作方法
删除原来全局定义的bookvideoc、addVideoc、onChangec、removeFormFieldsc,新增以下支持父级索引定位的操作方法:
// 新增子视频:指定对应主视频的索引 const addChildVideo = (parentIndex) => { const childTemplet = { book_All_details: "", number_of_chapters:"", chapter:'', video_title: "", description: "", video_url: "", video_image: "" } const updatedList = bookvideo.map((item, i) => { if(i === parentIndex) { return {...item, children: [...item.children, childTemplet]} } return item }) setBookvideo(updatedList) } // 修改子视频字段值:需要传入父索引、子索引 const onChangeChild = (e, parentIndex, childIndex) => { const updatedList = bookvideo.map((item, i) => { if(i === parentIndex) { return { ...item, children: item.children.map((child, j) => { if(j === childIndex) { return {...child, [e.target.name]: e.target.value} } return child }) } } return item }) setBookvideo(updatedList) } // 删除子视频:需要传入父索引、子索引 const removeChildVideo = (parentIndex, childIndex) => { const updatedList = bookvideo.map((item, i) => { if(i === parentIndex) { return { ...item, children: item.children.filter((_, j) => j !== childIndex) } } return item }) setBookvideo(updatedList) } // 原有主视频的操作方法保留即可,注意修改输入值绑定的问题 const onChange =(e ,index) =>{ const updateBookvideo = bookvideo.map((item ,i) => index == i ? {...item, [e.target.name]: e.target.value} : item ); setBookvideo(updateBookvideo); } const removeFormFields =(index) =>{ const filterbookvideo = bookvideo.filter((_, i) => i !== index); setBookvideo(filterbookvideo); } const addVideo = () =>{ setBookvideo([...bookvideo, {...videoTemplet}]) }
3. 调整渲染逻辑
修改JSX部分的绑定逻辑,子视频列表从当前主项的children字段读取,所有操作传入对应索引:
<Accordion.Body > <div class="mainform bg-info"> {bookvideo.map((element, index) => ( <div class="container" key={index}> <div class="form-group col-sm-4"> <label>Enter Chapter Name:</label> {/* 注意value绑定当前遍历的element属性,不要直接用bookvideo */} <input type="text" name="number_of_chapters" value={element.number_of_chapters} onChange={e => onChange(e,index)} class="form-control" placeholder="title" /> </div> <div class="row"> <div class="form-group col-sm-6"> <label>Title:</label> <input type="text" name="video_title" value={element.video_title} onChange={e => onChange(e,index)} class="form-control" placeholder="title" /> </div> <div class="form-group col-sm-6"> <label>Description:</label> <input type="text" name="description" value={element.description} onChange={e => onChange(e,index)} class="form-control" placeholder="authors" /> </div> </div> <div class="form-group"> <label>Thambnail image:</label> <input name ="video_image" value={element.video_image} onChange={e => onChange(e,index)} type="file" class="form-control" /> </div> <div class="form-group"> <label>Upload Video:</label> <input name="video_url" value={element.video_url} onChange={e => onChange(e,index)} type="file" class="form-control pb-4" /> </div> <br></br> {/* 子视频从当前主项的children读取 */} {element.children.map((child, indexc) => ( <div class="container bg-success" key={indexc}> <div className="main"> <div class="row"> <div class="form-group col-sm-6"> <label>Title:</label> <input type="text" name="video_title" value={child.video_title} onChange={e => onChangeChild(e, index, indexc)} class="form-control" placeholder="title" /> </div> <div class="form-group col-sm-6"> <label>Description:</label> <input type="text" name="description" value={child.description} onChange={e => onChangeChild(e, index, indexc)} class="form-control" placeholder="authors" /> </div> </div> <div class="form-group"> <label>Thambnail image:</label> <input name ="video_image" value={child.video_image} onChange={e => onChangeChild(e, index, indexc)} type="file" class="form-control" /> </div> <div class="form-group"> <label>Upload Video:</label> <input name="video_url" value={child.video_url} onChange={e => onChangeChild(e, index, indexc)} type="file" class="form-control pb-4" /> </div> <br></br> { indexc ? <button type="button" className="buttonremove remove" onClick={() => removeChildVideo(index, indexc)}>Remove</button> :null } </div> </div> ))} <div className="button-section" style={{textAlign:"center"}}> {/* 新增子视频传入当前主项索引 */} <button className="buttonsubmit add" type="button" onClick={() => addChildVideo(index)}><PlusOutlined /></button> </div> { index ? <button type="button" className="buttonremove remove" onClick={() => removeFormFields(index)}>Remove</button> : null } </div> ))} <div className="button-section" style={{textAlign:"center"}}> <button className="buttonsubmit add" type="button" onClick={addVideo}><PlusOutlined /></button> </div> </div> </Accordion.Body>
修改完成后每个主视频项的子列表完全独立,新增主项时子列表默认是空的,不会显示其他主项的子视频。
内容的提问来源于stack exchange,提问作者Ashutosh kumar
相关产品推荐
相关产品推荐

