如何在父组件中控制PureComponent子输入组件的值并提交?
如何在父组件中控制PureComponent实现的Input值并完成提交
问题场景
使用PureComponent实现了自定义Input组件,但父组件无法控制输入框的值,也无法在提交时获取输入内容,相关代码如下:
Input组件(index.jsx)
class Input extends PureComponent { constructor(props) { super(props); this.state = { value: props.value, name: props.value, }; this.setRef = this.setRef.bind(this); this.handleChange = this.handleChange.bind(this); } setRef(ref) { this.ref = ref; } handleChange(e) { const { name, onChange, type } = this.props; onChange(name, e.target.value); this.setState({ isInputError: checkError, value: e.target.value }); } render() { const { label, name, type} = this.props; return ( <div className="inputBox"> <input id={name} value={this.state.value} type={type} ref={this.setRef} onChange={this.handleChange} className="BlueInput" /> <label>{label}</label> </div> ); } } Input.propTypes = { label: PropTypes.string, name: PropTypes.string.isRequired, value: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), type: PropTypes.oneOf(["text", "password", "number", "price", "tel"]), onChange: PropTypes.func, } Input.defaultProps = { value: "", type: "text", onChange: () => { }, } export default Input;
父组件(Join.js)
function Join() { const [idMessage, setIdMessage] = useState(""); const [isId, setIsId] = useState(false); const onChangeId = (name, value) => { const currentId = value; const idRegExp = /^[a-zA-z0-9]{4,12}$/; if (!idRegExp.test(currentId)) { setIdMessage("Wrong format"); setIsId(false); } else { setIdMessage("You can use this"); setIsId(true); } } const handleSubmit = (e) => { e.preventDefault(); let formData = new FormData(); console.log(formData); alert("Join completed."); } return ( <div className="join-wrap"> <form encType="multipart/form-data" onSubmit={handleSubmit}> <Input name="id" label="ID" onChange={onChangeId} /> <p className={isId ? 'possible' : 'impossible'}>{idMessage}</p> <button type="submit">Join</button> </form> </div> ) } export default Join;
解决方案
核心是将Input组件改为受控组件,让父组件完全掌控输入值的状态:
1. 修改Input组件为受控组件
移除组件内部维护的value状态,直接使用props传入的value,仅保留必要的内部状态(如错误状态):
import React, { PureComponent } from 'react'; import PropTypes from 'prop-types'; class Input extends PureComponent { constructor(props) { super(props); // 仅保留错误状态等内部需要维护的状态 this.state = { isInputError: false, }; this.setRef = this.setRef.bind(this); this.handleChange = this.handleChange.bind(this); } // 监听props.value变化,同步处理内部状态(比如清除错误) componentDidUpdate(prevProps) { if (prevProps.value !== this.props.value) { this.setState({ isInputError: false }); } } setRef(ref) { this.ref = ref; } handleChange(e) { const { onChange } = this.props; const inputValue = e.target.value; // 替换为你的实际校验逻辑 const checkError = !/^[a-zA-Z0-9]{4,12}$/.test(inputValue); this.setState({ isInputError: checkError }); // 通知父组件更新值 onChange(this.props.name, inputValue); } render() { const { label, name, type, value } = this.props; const { isInputError } = this.state; return ( <div className="inputBox"> <input id={name} value={value} // 直接使用props传递的值 type={type} ref={this.setRef} onChange={this.handleChange} className={`BlueInput ${isInputError ? 'input-error' : ''}`} /> <label>{label}</label> </div> ); } } Input.propTypes = { label: PropTypes.string, name: PropTypes.string.isRequired, value: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), type: PropTypes.oneOf(["text", "password", "number", "price", "tel"]), onChange: PropTypes.func, } Input.defaultProps = { value: "", type: "text", onChange: () => { }, } export default Input;
2. 父组件维护输入状态并传递给Input
在父组件中添加状态保存输入值,通过value属性传递给Input,提交时直接使用该状态值:
import React, { useState } from 'react'; import Input from './Input'; function Join() { const [userId, setUserId] = useState(""); // 新增状态保存输入的ID const [idMessage, setIdMessage] = useState(""); const [isId, setIsId] = useState(false); const onChangeId = (name, value) => { setUserId(value); // 同步更新父组件状态 const idRegExp = /^[a-zA-Z0-9]{4,12}$/; if (!idRegExp.test(value)) { setIdMessage("Wrong format"); setIsId(false); } else { setIdMessage("You can use this"); setIsId(true); } } const handleSubmit = (e) => { e.preventDefault(); // 直接使用父组件中的userId获取输入值 const formData = new FormData(); formData.append('id', userId); console.log('提交的ID:', userId); console.log('FormData内容:', formData); alert("Join completed."); // 此处可添加后端提交逻辑,如fetch('/api/join', { method: 'POST', body: formData }) } return ( <div className="join-wrap"> <form encType="multipart/form-data" onSubmit={handleSubmit}> {/* 传递value属性,实现受控 */} <Input name="id" label="ID" value={userId} onChange={onChangeId} /> <p className={isId ? 'possible' : 'impossible'}>{idMessage}</p> {/* 可选:格式不正确时禁用提交按钮 */} <button type="submit" disabled={!isId}>Join</button> </form> </div> ) } export default Join;
关键说明
- 受控组件的核心逻辑:输入框的值由父组件state驱动,Input仅负责渲染和通知值变化,不维护自身的value状态,确保父组件完全控制输入内容。
- 父组件通过
value传递当前值,onChange接收变化后的值并更新state,实现双向同步,随时可以修改输入值(如重置、预填充)。 - 提交时直接使用父组件中维护的状态变量,无需从DOM读取值,符合React的状态管理规范。
内容的提问来源于stack exchange,提问作者Felix Y
相关产品推荐
相关产品推荐

