受控组件:通过组件的状态与属性的改变来控制组件
不可控组件:直接通过底层的dom来控制组件(具体来说就是通过绑定再底层dom上的方法来实现的,比如说ref,onChange)
受控组件
function validate(name, email, password) { // we are going to store errors for all fields // in a signle array const errors = []; if (name.length === 0) { errors.push("Name can't be empty"); } if (email.length < 5) { errors.push("Email should be at least 5 charcters long"); } if (email.split('').filter(x => x === '@').length !== 1) { errors.push("Email should contain a @"); } if (email.indexOf('.') === -1) { errors.push("Email should contain at least one dot"); } if (password.length < 6) { errors.push("Password should be at least 6 characters long"); } return errors; } class SignUpForm extends React.Component { constructor() { super(); this.state = { name: '', email: '', password: '', errors: [], }; this.handleSubmit = this.handleSubmit.bind(this); } handleSubmit(e) { e.preventDefault(); const { name, email, password } = this.state; const errors = validate(name, email, password); if (errors.length > 0) { this.setState({ errors }); return; } // submit the data... } render() { const { errors } = this.state; return ( <form onSubmit={this.handleSubmit}> {errors.map(error => ( <p key={error}>Error: {error}</p> ))} <input value={this.state.name} onChange={evt => this.setState({ name: evt.target.value })} type="text" placeholder="Name" /> <input value={this.state.email} onChange={evt => this.setState({ email: evt.target.value })} type="text" placeholder="Email" /> <input value={this.state.password} onChange={evt => this.setState({ password: evt.target.value })} type="password" placeholder="Password" /> <button type="submit">Submit</button> </form> ); } } ReactDOM.render(<SignUpForm />, document.body);
不可控组件
function validate(name, email, password) { // we are going to store errors for all fields // in a signle array const errors = []; if (name.length === 0) { errors.push("Name can't be empty"); } if (email.length < 5) { errors.push("Email should be at least 5 charcters long"); } if (email.split('').filter(x => x === '@').length !== 1) { errors.push("Email should contain a @"); } if (email.indexOf('.') === -1) { errors.push("Email should contain at least one dot"); } if (password.length < 6) { errors.push("Password should be at least 6 characters long"); } return errors; } class SignUpForm extends React.Component { constructor() { super(); this.state = { errors: [], }; this.handleSubmit = this.handleSubmit.bind(this); } handleSubmit(e) { e.preventDefault(); const name = ReactDOM.findDOMNode(this._nameInput).value; const email = ReactDOM.findDOMNode(this._emailInput).value; const password = ReactDOM.findDOMNode(this._passwordInput).value; const errors = validate(name, email, password); if (errors.length > 0) { this.setState({ errors }); return; } // submit the data... } render() { const { errors } = this.state; return ( <form onSubmit={this.handleSubmit}> {errors.map(error => ( <p key={error}>Error: {error}</p> ))} <input ref={nameInput => this._nameInput = nameInput} type="text" placeholder="Name" /> <input ref={emailInput => this._emailInput = emailInput} type="text" placeholder="Email" /> <input ref={passwordInput => this._passwordInput = passwordInput} type="password" placeholder="Password" /> <button type="submit">Submit</button> </form> ); } } ReactDOM.render(<SignUpForm />, document.body);
在使用非受控组件的时候可以通过设置默认值来对dom的value进行初始化操作
class NameForm extends React.Component { constructor(props) { super(props); this.handleSubmit = this.handleSubmit.bind(this); } handleSubmit(event) { alert('A name was submitted: ' + this.input.value); event.preventDefault(); } render() { return ( <form onSubmit={this.handleSubmit}> <label> Name: <input defaultValue="Bob" type="text" ref={(input) => this.input = input} /> </label> <input type="submit" value="Submit" /> </form> ); } }
另外, <input type="checkbox">
和 <input type="radio">
支持 defaultChecked
, <select>
和<textarea>
支持 defaultValue
.
访问文件的实例(非控制组件)
class FileInput extends React.Component { constructor(props) { super(props); this.handleSubmit = this.handleSubmit.bind(this); } handleSubmit(event) { event.preventDefault(); alert( `Selected file - ${this.fileInput.files[0].name}` ); } render() { return ( <form onSubmit={this.handleSubmit}> <label> Upload file: <input type="file" ref={input => { this.fileInput = input; }} /> </label> <br /> <button type="submit">Submit</button> </form> ); } } ReactDOM.render( <FileInput />, document.getElementById('root') );
他们的应用场景对比:
结论:尽可能的使用受控组件来进行表单提交的操作,除非符合本文中给出的不可控例子或者为单次提交检验的form操作。(不可控实现的原理其实就是在ref的回掉中把当前的dom对象赋给组件的某个属性,通过该属性进而操作dom对象)
参考:https://goshakkk.name/controlled-vs-uncontrolled-inputs-react/