preface

In the development process, we can’t avoid the form submission data scenario. React has managed and uncontrolled components that are used to submit form data. What’s the difference?

Uncontrolled component

What can be called an uncontrolled component?

To write an uncontrolled component, rather than writing a data handler for every status update, you can use the ref to fetch form data from the DOM node.

If you don’t know how to use ref, look at the properties of state, props, and ref in this article

As the saying goes, I can use ref to get a value from a DOM element, for example, the input tag binding ref assigns a value to a value by ref. This is not controllable, but it is not controlled by code. Let’s look at an example.

import React, { Component } from "react";

export default class App extends Component {
  handleSubmit = (event: React.FormEvent<HTMLFormElement>) = > {
    event.preventDefault();
    const { username, password } = this;
    alert('The username you entered is:${username! .value}, your password is:${password! .value}`);
  };
  username: HTMLInputElement | null | undefined;
  password: HTMLInputElement | null | undefined;
  render() {
    return (
      <form onSubmit={this.handleSubmit}>User name:<input ref={(c)= >(this.username = c)} defaultValue="admin" name="username" type="text"<input ref={(c)= > (this.password = c)} defaultValue="123" type="password" name="password" />
        <button>The login</button>
      </form>); }}Copy the code

Username = c; this. Username = c; this. Username = c; Anyway, I have to pack up and get ready to go in.

See if there is any kind of VUE V-model, you input I bind, you change I also change.

The controlled components

What is a controlled component?

The React component that renders the form also controls what happens to the form during user input. The form input elements that React controls their values in this way are called “controlled components.”

The value of a component is stored in state. When a change occurs during component input, the input value is retrieved through the onChange event and can only be updated by using setState() to display the new value within the component

For example, our common form elements ,

input

Let’s look at the next example:

import React, { Component } from "react";

export default class example1 extends Component {
  state: Readonly<{ username: string} > = {username: "Week star"};render() {
    return <input name="username" value={this.state.username} />; }}Copy the code

The value is controlled by this.state.username. When the user enters new content, this.state.username is not automatically updated, so the content in the input will not change.

And an error is reported on the console:

Basically, you give a value, but you don’t do it with onChange, so either you change the value to defaultValue or you add the onChange event. Then we will follow the meaning to modify:

import React, { ChangeEvent, Component, FormEvent } from "react";

export default class example1 extends Component {
  state: Readonly<{ username: string; password: string} > = {username: ""./ / user name
    password: ""./ / password
  };
  handleSubmit = (event: FormEvent<HTMLFormElement>) = > {
    event.preventDefault();
    const { username, password } = this.state;
    alert('The username you entered is:${username}, your password is:${password}`);
  };
  
  // Save the user name to the status
  saveUsername = (event: ChangeEvent<HTMLInputElement>) = > {
    this.setState({ username: event.target.value });
  };

  // Save the password to the status
  savePassword = (event: ChangeEvent<HTMLInputElement>) = > {
    this.setState({ password: event.target.value });
  };

  render() {
    return (
      <form onSubmit={this.handleSubmit}>User name:<input onChange={this.saveUsername} type="text" name="username" />Password:<input onChange={this.savePassword} type="password" name="password" />
        <button>The login</button>
      </form>); }}Copy the code

The state and UI are now updated regardless of what the user enters, and we can use this.state.username elsewhere in the component to retrieve the contents of the input, and we can also modify the contents of the input by using this.setstate ().

Textarea tags also use value and onChange, which interested parties can verify for themselves

select

The example above shows an input element, but for select form elements, React converting them to controlled components might be a bit different from native HTML.

In native, we use selected by default for a select option, such as the following:

import React, { Component } from "react";

export default class example3 extends Component {
  render() {
    return (
      <>
        <select>
          <option value="grapefruit">Week star</option>
          <option value="lime">Athena chu</option>
          <option selected value="coconut">Qing-xia li</option>
          <option value="mango">Zhang min</option>
        </select>
      </>); }}Copy the code

However, React does not use the selected attribute. Instead, it uses the value attribute on the root SELECT tag. This is easier in controlled components because you only need to update it in the root tag. Otherwise the console will get this error

The correct answer would be:

import React, { ChangeEvent, Component, FormEvent } from "react";

export default class example3 extends Component {
  state: Readonly<{
    value: string; } > = {value: "Li Qingxia"}; handleChange =(event: ChangeEvent<HTMLSelectElement>) = > {
    this.setState({ value: event.target.value });
  };

  handleSubmit = (event: FormEvent<HTMLFormElement>) = > {
    alert("Which flavor do you prefer?" + this.state.value);
    event.preventDefault();
  };
  render() {
    return (
      <>
        <form onSubmit={this.handleSubmit}>
          <label>Choose your favorite flavor:<select value={this.state.value} onChange={this.handleChange}>
              <option value="Week star">Week star</option>
              <option value="Athena chu">Athena chu</option>
              <option value="Li Qingxia">Qing-xia li</option>
              <option value="Zhang">Zhang min</option>
            </select>
          </label>
          <button>submit</button>
        </form>
      </>); }}Copy the code

The ones above are just single choices, if we need multiple choices

  • toselectLabel setmultipleProperties fortrue
  • selectThe labelvalueThe binding value is an array

Take this example:

import React, { ChangeEvent, Component, FormEvent } from "react";

export default class example3 extends Component {
  state: Readonly<{
    value: string[]; } > = {value: ["Li Qingxia"]}; handleChange =(event: ChangeEvent<HTMLSelectElement>) = > {
    console.log(event.target.value);
    const val = event.target.value;
    const oldValue = this.state.value;
    const i = this.state.value.indexOf(val);
    const newValue = i > -1 ? [...oldValue].splice(i, 1) : [...oldValue, val];
    this.setState({ value: newValue });
  };

  handleSubmit = (event: FormEvent<HTMLFormElement>) = > {
    alert("What do you like?" + this.state.value);
    event.preventDefault();
  };
  render() {
    return (
      <>
        <form onSubmit={this.handleSubmit}>
          <label>Choose what you like:<select multiple={true} value={this.state.value} onChange={this.handleChange}>
              <option value="Week star">Week star</option>
              <option value="Athena chu">Athena chu</option>
              <option value="Li Qingxia">Qing-xia li</option>
              <option value="Zhang">Zhang min</option>
            </select>
          </label>
          <button>submit</button>
        </form>
      </>); }}Copy the code

If you think you’re done here, you’re wrong.

<input type="file" />

There will always be something that jumps out of bounds, like when our input tag type property is file, it’s an uncontrolled component.

It is always an uncontrolled component for a form control of type File because its value can only be set by the user, not programmatically.

For example, I now want to control it with status updates:

import React, { ChangeEvent, Component, FormEvent } from "react";

export default class example4 extends Component {
  state: Readonly<{ files: []}> = {files: [],}; handleSubmit =(e: FormEvent<HTMLFormElement>) = > {
    e.preventDefault();
  };
  handleFile = (e: ChangeEvent<HTMLInputElement>) = > {
    console.log(e.target.files);
    constfiles = [...e.target.files!] ;console.log(files);
    this.setState({
      files,
    });
  };
  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <input type="file" value={this.state.files} onChange={(e)= > this.handleFile(e)} />
        <button>submit</button>
      </form>); }}Copy the code

After selecting the file, I tried to update it with setState and got an error:

So we should use the uncontrolled component method to get its value like this:

import React, { ChangeEvent, Component, FormEvent } from "react";

export default class example4 extends Component {
  fileRef = React.createRef<HTMLInputElement>();
  state: Readonly<{ files: []}> = {files: [],}; handleSubmit =(e: FormEvent<HTMLFormElement>) = > {
    e.preventDefault();
    console.log("We can get the value of file.".this.fileRef.current! .files); };render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <input type="file" ref={this.fileRef} />
        <button>submit</button>
      </form>); }}Copy the code

The files obtained here is an array. Of course, if you don’t have multiple selection enabled, the array length is always 1.

<input type="file" multiple ref={this.fileRef} />
Copy the code

conclusion

OK, I believe you have a clear idea of these two groups of concepts. What? You ask me the actual application scenario?

B: well… Most of the time it is recommended to use a controlled component to implement forms, because the React component handles the form data. Of course, if you choose an uncontrolled component, the form data is handled by the DOM itself.