表单
在HTML中,input、textarea、select这类标签都是会产生数据的。
受控组件
在HTML中,表单元素(如<input>、<textarea>和<select>)通常自己维护state,并根据用户输入进行更新。
而在React中,可变状态通常保存在组件的state属性中,并且只能通过使用setState进行更新。
把两者结合起来,使React的state成为“唯一的数据源”。渲染表单的React组件还控制着用户输入过程中表单发生的操作。被React以这种方式控制取值的表单输入元素就叫做“受控组件”。
处理单个输入
查看示例代码
import React from "react";
export default class App extends React.Component {
  constructor() {
    super();
    this.state = {
      name: "",
    };
  }
  submitForm(event) {
    event.preventDefault();
    console.log("提交的名字:" + this.state.name);
  }
  handleChange(event) {
    console.log(event.target.value);
    this.setState({ name: event.target.value });
  }
  render() {
    return (
      <form onSubmit={this.submitForm.bind(this)}>
        <label htmlFor="name">
          名字:
          <input type="text" id="name" value={this.state.value} onChange={this.handleChange.bind(this)} />
        </label>
        <input type="submit" value="提交" />
      </form>
    );
  }
}
import { useState } from "react";
const App = () => {
  const [name, setName] = useState("");
  const submitForm = event => {
    event.preventDefault();
    console.log("提交的名字:" + name);
  };
  const handleChange = event => {
    console.log(event.target.value);
    setName(event.target.value);
  };
  return (
    <>
      <form onSubmit={submitForm}>
        <label htmlFor="name">
          名字:
          <input type="text" id="name" value={name} onChange={handleChange} />
        </label>
        <input type="submit" value="提交" />
      </form>
    </>
  );
};
export default App;
处理多个输入
查看示例代码
import React from "react";
export default class App extends React.Component {
  constructor() {
    super();
    this.state = {
      username: "", //这里定义的变量名,要与input标签里定义的name值一样
      password: "",
    };
  }
  submitForm(event) {
    event.preventDefault();
    console.log("提交的表单:" + JSON.stringify(this.state));
  }
  handleChange(event) {
    console.log(event.target.name, event.target.value);
    this.setState({ [event.target.name]: event.target.value });
  }
  render() {
    return (
      <form onSubmit={this.submitForm.bind(this)}>
        <label htmlFor="name">
          用户名:
          <input type="text" id="name" name="username" value={this.state.value} onChange={this.handleChange.bind(this)} />
        </label>
        <br />
        <label htmlFor="pwd">
          密码:
          <input type="password" id="pwd" name="password" value={this.state.value} onChange={this.handleChange.bind(this)} />
        </label>
        <br />
        <input type="submit" value="提交" />
      </form>
    );
  }
}
import { useState } from "react";
const App = () => {
  const [form, setForm] = useState({ username: "", password: "" });
  const submitForm = event => {
    event.preventDefault();
    console.log("提交的表单:" + JSON.stringify(form));
  };
  const handleChange = event => {
    console.log(event.target.name, event.target.value);
    setForm({
      ...form,
      [event.target.name]: event.target.value,
    });
  };
  return (
    <>
      <form onSubmit={submitForm}>
        <label htmlFor="name">
          名字:
          <input type="text" id="name" name="username" value={form.username} onChange={handleChange} />
        </label>
        <br />
        <label htmlFor="pwd">
          密码:
          <input type="password" id="pwd" name="password" value={form.password} onChange={handleChange} />
        </label>
        <br />
        <input type="submit" value="提交" />
      </form>
    </>
  );
};
export default App;
非受控组件
在大多数情况下,Reacr推荐使用受控组件来处理表单数据。
在一个受控组件中,表单数据是由 React 组件来管理的。另一种替代方案是使用非受控组件,这时表单数据将交由 DOM 节点来处理。
要编写一个非受控组件,而不是为每个状态更新都编写数据处理函数,你可以 使用 ref 来从 DOM 节点中获取表单数据。
查看示例代码
import React from "react";
export default class App extends React.Component {
  constructor() {
    super();
    this.username = React.createRef();
    this.password = React.createRef();
  }
  submitForm(event) {
    event.preventDefault();
    console.log("提交的用户名:" + this.username.current.value);
    console.log("提交的密码:" + this.password.current.value);
  }
  render() {
    return (
      <form onSubmit={this.submitForm.bind(this)}>
        <label htmlFor="name">
          用户名:
          <input type="text" id="name" ref={this.username} />
        </label>
        <br />
        <label htmlFor="pwd">
          密码:
          <input type="password" id="pwd" ref={this.password} />
        </label>
        <br />
        <input type="submit" value="提交" />
      </form>
    );
  }
}
import React from "react";
const App = () => {
  const username = React.createRef();
  const password = React.createRef();
  const submitForm = event => {
    event.preventDefault();
    console.log("提交的用户名:" + username.current.value);
    console.log("提交的密码:" + password.current.value);
  };
  return (
    <>
      <form onSubmit={submitForm}>
        <label htmlFor="name">
          名字:
          <input type="text" id="name" ref={username} />
        </label>
        <br />
        <label htmlFor="pwd">
          密码:
          <input type="password" id="pwd" ref={password} />
        </label>
        <br />
        <input type="submit" value="提交" />
      </form>
    </>
  );
};
export default App;
默认值
在 React 渲染生命周期时,表单元素上的 value 将会覆盖 DOM 节点中的值。
在非受控组件中,你如果希望 React 能赋予组件一个初始值,但是不去控制后续的更新。 在这种情况下, 你可以指定一个 defaultValue 属性,而不是 value。
在一个组件已经挂载之后去更新 defaultValue 属性的值,不会造成 DOM 上值的任何更新。
见下两种定义默认值的方法:
查看示例代码
import React from "react";
const App = () => {
  const username = React.createRef();
  const password = React.createRef();
  const submitForm = event => {
    event.preventDefault();
    console.log("提交的用户名:" + username.current.value);
    console.log("提交的密码:" + password.current.value);
  };
  const defaultPassword = "123";
  return (
    <>
      <form onSubmit={submitForm}>
        <label htmlFor="name">
          名字:
          <input type="text" id="name" ref={username} defaultValue="admin" />
        </label>
        <br />
        <label htmlFor="pwd">
          密码:
          <input type="password" id="pwd" ref={password} defaultValue={defaultPassword} />
        </label>
        <br />
        <input type="submit" value="提交" />
      </form>
    </>
  );
};
export default App;
同样,<input type="checkbox"> 和 <input type="radio"> 支持 defaultChecked,<select> 和 <textarea> 支持 defaultValue。
文件输入
在 HTML 中,<input type="file"> 可以让用户选择一个或多个文件上传到服务器,或者通过使用 File API 进行操作。
在 React 中,<input type="file" /> 始终是一个非受控组件,因为它的值只能由用户设置,而不能通过代码控制。
下面的例子显示了如何创建一个 DOM 节点的 ref 从而在提交表单时获取文件的信息:
查看示例代码
import React from "react";
export default class App extends React.Component {
  constructor() {
    super();
    this.fileInput = React.createRef();
  }
  handleSubmit(event) {
    event.preventDefault();
    console.log(this.fileInput.current.files[0]);
  }
  render() {
    return (
      <form onSubmit={this.handleSubmit.bind(this)}>
        <label>
          上传文件:
          <input type="file" ref={this.fileInput} />
        </label>
        <br />
        <button type="submit">提交</button>
      </form>
    );
  }
}
import React from "react";
const App = () => {
  const fileInput = React.createRef();
  const handleSubmit = event => {
    event.preventDefault();
    console.log(fileInput.current.files[0]);
  };
  return (
    <>
      <form onSubmit={handleSubmit}>
        <label>
          上传文件:
          <input type="file" ref={fileInput} />
        </label>
        <br />
        <button type="submit">提交</button>
      </form>
    </>
  );
};
export default App;
