受控组件:通过组件的状态与属性的改变来控制组件

不可控组件:直接通过底层的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/

           https://reactjs.org/docs/uncontrolled-components.html

posted on 2018-03-09 13:56  爬虫一只  阅读(846)  评论(0编辑  收藏  举报