ReactJS表单提交后无法更新名人信息:id.findIndex报错排查
问题描述
我有一个存储名人信息的数据库,不同名人的信息展示在不同的折叠面板(Accordion)中,每个折叠面板都配有编辑按钮,点击按钮会打开表单编辑面板内的各类信息字段。
现在无法保存并同步表单输入的内容,尝试保存详情时,在AccordionForm.jsx中遇到以下错误:
id.findIndex is not a function
我怀疑是无法从数据库中获取id导致的。
相关代码
Home.jsx
return ( <div> <div className="app_header"> <p>Celebrities Wiki List</p> </div> {data.map( ({ id, first, last, dob, gender, picture, country, description }) => ( <Accordion key={id} id={id} first={first} last={last} dob={dob} gender={gender} picture={picture} country={country} description={description} /> ), )} </div> );
Accordion.jsx
const Accordion = (props) => { const [isActive, setIsActive] = React.useState(false); const [showModal, setShowModal] = React.useState(false); return ( <div className="accordion-container"> <div className="accordion-item"> <div className="accordion-title" onClick={() => setIsActive(!isActive)}> <div className="accordion-head"> <img src={props.picture} alt="celebrity-img" /> <div className="name"> {props.first} {props.last} </div> </div> <div> {isActive ? ( <SlArrowUp fontSize={20} color="#a4a597" cursor="pointer" /> ) : ( <SlArrowDown fontSize={20} color="#a4a597" cursor="pointer" /> )} </div> </div> {showModal ? ( <AccordionForm id={props.id} age={props.age} gender={props.gender} country={props.country} description={props.description} updateAccordion={props.updateAccordion} onClose={() => setShowModal(false)} /> ) : ( <> {isActive && ( <div className="accordion-body"> <div className="accordion-info"> <div className="age"> <p className="info-tag">Age</p> <p className="content-text">{props.dob} Years</p> </div> <div className="gender"> <p className="info-tag">Gender</p> <p className="content-text">{props.gender}</p> </div> <div className="country"> <p className="info-tag">Country</p> <p className="content-text">{props.country}</p> </div> </div> <div className="accordion-content"> <p className="info-tag">Description</p> <p className="content-text">{props.description}</p> </div> <div className="accordion-buttons"> <BsTrash3 fontSize={20} color="red" cursor="pointer" /> <BsPencil fontSize={20} color="blue" cursor="pointer" onClick={() => setShowModal(true)} /> </div> </div> )} </> )} </div> </div> ); };
AccordionForm.jsx
const AccordionForm = (props) => { const [values, setValues] = React.useState({ ...props }); const updateAccordion = (id) => { const index = id.findIndex((item) => item.id === id); if (index < 0) return; }; React.useEffect(() => { if ( values.id === props.id && values.first === props.first && values.last === props.last && values.description === props.description && values.country === props.country && values.age === props.age && values.gender === props.gender ) return; updateAccordion(props.id, values); }, [values]); return ( <Modal onClose={() => props.onClose()}> <div className="accordion-body"> <div className="accordion-info"> <div className="age"> <p className="info-tag">Age</p> <Editable text={values.age} default={values.age} placeholder="Enter Age" onSubmit={(value) => setValues({ ...values, age: value })} /> </div> <div className="gender"> <p className="info-tag">Gender</p> <Editable text={values.gender} default={values.gender} placeholder="State Your Gender" onSubmit={(value) => setValues({ ...values, gender: value })} /> </div> <div className="country"> <p className="info-tag">Country</p> <Editable text={values.country} default={values.country} placeholder="Enter Country" onSubmit={(value) => setValues({ ...values, country: value })} /> </div> </div> <div className="accordion-content"> <p className="info-tag">Description</p> <Editable name={values.description} default={values.description} placeholder="Enter Description" onSubmit={(value) => setValues({ ...values, description: value })} /> </div> <div className="accordion-buttons"> <button type="submit"> <img className="form-check" type src={check} alt="save" /> </button> <button> <img className="form-cross" src={cross} alt="close" onClick={() => props.onClose()} /> </button> </div> </div> </Modal> ); };
Modal.jsx
const Modal = (props) => { return ( <div className="modal" onClick={() => (props.onClose ? props.onClose() : "")} > <div className="modal_content" onClick={(event) => event.stopPropagation()} > {props.children} </div> </div> ); };
问题原因与修复
核心错误原因
id.findIndex is not a function 错误的直接原因是:在AccordionForm.jsx的updateAccordion函数中,你把单个id值当成了数组来调用findIndex方法。props.id是单个名人的id(字符串或数字类型),而findIndex是数组的专属方法,因此触发报错。
同时还存在几个关联问题:
updateAccordion函数定义只接收id参数,但调用时传了props.id和values两个参数,参数不匹配。- 数据源(
data数组)未传递到更新逻辑中,updateAccordion找不到要修改的目标数组。 Home.jsx到Accordion再到AccordionForm的updateAccordion方法传递链断裂,Accordion未接收并传递该方法。Accordion里用props.dob展示年龄,但传给AccordionForm的是props.age,字段不匹配。
分步修复
1. 修复数据源与更新逻辑(Home.jsx)
将data改为状态变量,定义更新函数并传递给Accordion组件:
const [data, setData] = React.useState(你的初始名人数据); const updateAccordion = (id, updatedValues) => { setData(prevData => { return prevData.map(item => { if (item.id === id) { return { ...item, ...updatedValues }; } return item; }); }); }; // 渲染时传递updateAccordion给Accordion {data.map( ({ id, first, last, dob, gender, picture, country, description }) => ( <Accordion key={id} id={id} first={first} last={last} dob={dob} gender={gender} picture={picture} country={country} description={description} updateAccordion={updateAccordion} /> ), )}
2. 修复Accordion组件的字段传递(Accordion.jsx)
将展示的dob作为age传给AccordionForm,保持字段一致:
<AccordionForm id={props.id} age={props.dob} // 替换props.age为props.dob,和面板展示内容匹配 gender={props.gender} country={props.country} description={props.description} updateAccordion={props.updateAccordion} onClose={() => setShowModal(false)} />
3. 重构AccordionForm.jsx的更新逻辑
删除组件内部无效的updateAccordion函数,直接使用props传递的更新方法,改用按钮点击触发保存:
const AccordionForm = (props) => { const [values, setValues] = React.useState({ id: props.id, age: props.age, gender: props.gender, country: props.country, description: props.description }); const handleSave = () => { props.updateAccordion(props.id, values); props.onClose(); }; return ( <Modal onClose={() => props.onClose()}> <div className="accordion-body"> <div className="accordion-info"> <div className="age"> <p className="info-tag">Age</p> <Editable text={values.age} default={values.age} placeholder="Enter Age" onSubmit={(value) => setValues({ ...values, age: value })} /> </div> <div className="gender"> <p className="info-tag">Gender</p> <Editable text={values.gender} default={values.gender} placeholder="State Your Gender" onSubmit={(value) => setValues({ ...values, gender: value })} /> </div> <div className="country"> <p className="info-tag">Country</p> <Editable text={values.country} default={values.country} placeholder="Enter Country" onSubmit={(value) => setValues({ ...values, country: value })} /> </div> </div> <div className="accordion-content"> <p className="info-tag">Description</p> <Editable text={values.description} // 替换name为text,和其他字段属性一致 default={values.description} placeholder="Enter Description" onSubmit={(value) => setValues({ ...values, description: value })} /> </div> <div className="accordion-buttons"> <button type="button" onClick={handleSave}> <img className="form-check" src={check} alt="save" /> </button> <button> <img className="form-cross" src={cross} alt="close" onClick={() => props.onClose()} /> </button> </div> </div> </Modal> ); };
4. 额外优化点
- 移除原表单按钮的
type="submit"(无<form>标签时无效),改为type="button"并绑定handleSave事件。 - 统一
Editable组件的属性名,将描述字段的name改为text,保持一致性。
内容的提问来源于stack exchange,提问作者SE1822
相关产品推荐
相关产品推荐

