React开发:如何从父组件重置子表单组件的选中状态?
问题核心原因
你当前子组件的选中状态存储在自身内部state中,和父组件Formik维护的表单状态完全独立,Formik的表单重置操作无法同步修改子组件内部state,所以会出现重置失效的问题。另外你现有代码还存在两处逻辑缺陷:
- 提交表单时你读取的是
this.state而非Formik提供的values,无法拿到正确的表单字段值 - 子组件单选逻辑错误,选中新选项后旧选项的
checked属性不会被重置为false,会出现同时选中的情况
方案1:最小改动适配(基于ref调用子组件方法)
不需要重构现有状态逻辑,只需要新增少量代码即可实现重置:
第一步:修改父组件代码
export default class MainForm extends Component { constructor(props) { super(props); // 新增子组件ref this.exhibitorsRef = React.createRef(); } render() { return ( <Container> <Formik initialValues={{ exhibitors: 0, }} onSubmit={async (values, {setFieldValue, resetForm}) => { this.setState({loading: true}) const api = process.env.REACT_APP_API_ENDPOINT; // 修复:提交数据用Formik的values而非this.state const data = JSON.stringify(values) const headers = { 'Content-Type': 'application/json', } axios .post(api, data, { headers: headers, timeout: 10000 }) .then((response) => { // 调用Formik内置重置方法清空表单值 resetForm(); // 调用子组件暴露的重置方法清空选中状态 this.exhibitorsRef.current.resetCheckState(); window.scrollTo(0, 0) console.log(response) }) .catch((error) => { console.log(error) }) }} > {({values, setFieldValue, setFieldTouched}) => ( <Form id="platform-match"> {/* 给子组件绑定ref */} <Exhibitors ref={this.exhibitorsRef} onChange={setFieldValue} /> <Row> <Col> <button type="submit" className="checkbox-label submit"> Submit </button> </Col> </Row> </Form> )} </Formik> </Container> ) } }
第二步:修改子组件代码
export default class Exhibitors extends Component { state = { exhibitors: [ {id: 1, value: "true", label: "YES", checked: false}, {id: 2, value: "false", label: "NO", checked: false}, ] } handleChange = value => { this.props.onChange("exhibitors", (value.target.value === 'true')); this.setState(prevState => ({ exhibitors: prevState.exhibitors.map( // 修复单选逻辑:非选中项同步设为false el => el.value === value.target.value ? {...el, checked: true} : {...el, checked: false} ) })) }; // 新增对外暴露的重置方法 resetCheckState = () => { this.setState(prevState => ({ exhibitors: prevState.exhibitors.map(el => ({...el, checked: false})) })) } render() { return ( <div> <Row> <Col> <h4 className="ui centered question-header text-center">DO YOU HAVE EXHIBITORS?</h4> </Col> </Row> <Row> { this.state.exhibitors.map((type) => { return (<Radio name="exhibitors" key={type.value} onChange={this.handleChange} {...type} />) }) } </Row> </div> ) } }
方案2:更合理的状态管理(子组件完全托管状态到Formik)
从设计层面消除状态不同步的问题,子组件不再自己维护选中状态,所有状态完全由Formik管理:
子组件可以直接通过props接收Formik的values,渲染时直接根据values.exhibitors的值判断每个选项的checked属性,不需要内部state,Formik调用resetForm时子组件会自动更新选中状态,不需要额外的重置逻辑。
内容的提问来源于stack exchange,提问作者N P
相关产品推荐
相关产品推荐

