1、受控组件

React 的 state 成为“唯一数据源”。渲染表单的 React 组件还控制着用户输入过程中表单发生的操作。被 React 以这种方式控制取值的表单输入元素就叫做“受控组件”。
在 React 中,可变状态(mutable state)通常保存在组件的 state 属性中,并且只能通过使用 [setState()](https://zh-hans.reactjs.org/docs/react-component.html#setstate)来更新。
表单元素(如<input><textarea><select>)之类的表单元素通常自己维护 state,并根据用户输入进行更新。

A.input标签

  1. class NameForm extends React.Component {
  2. constructor(props) {
  3. super(props);
  4. this.state = {value: ''};
  5. this.handleChange = this.handleChange.bind(this);
  6. this.handleSubmit = this.handleSubmit.bind(this);
  7. }
  8. handleChange(event) {
  9. this.setState({value: event.target.value});
  10. }
  11. handleSubmit(event) {
  12. alert('提交的名字: ' + this.state.value);
  13. event.preventDefault();
  14. }
  15. render() {
  16. return (
  17. <form onSubmit={this.handleSubmit}>
  18. <label>
  19. 名字:
  20. <input type="text" value={this.state.value} onChange={this.handleChange} />
  21. </label>
  22. <input type="submit" value="提交" />
  23. </form>
  24. );
  25. }
  26. }

由于在表单元素上设置了 value 属性,因此显示的值将始终为 this.state.value,这使得 React 的 state 成为唯一数据源。由于 handlechange 在每次按键时都会执行并更新 React 的 state,因此显示的值将随着用户输入而更新。
对于受控组件来说,每个 state 突变都有一个相关的处理函数。这方便了修改或验证用户输入。例如,强制要求所有名称都用大写字母书写,可以将 handlechange 改写为:

  1. handleChange(event) {
  2. this.setState({value: event.target.value.toUpperCase()});
  3. }

B.textarea 标签

  1. class EssayForm extends React.Component {
  2. constructor(props) {
  3. super(props);
  4. this.state = {
  5. value: '请撰写一篇关于你喜欢的 DOM 元素的文章.'
  6. };
  7. this.handleChange = this.handleChange.bind(this);
  8. this.handleSubmit = this.handleSubmit.bind(this);
  9. }
  10. handleChange(event) {
  11. this.setState({value: event.target.value});
  12. }
  13. handleSubmit(event) {
  14. alert('提交的文章: ' + this.state.value);
  15. event.preventDefault();
  16. }
  17. render() {
  18. return (
  19. <form onSubmit={this.handleSubmit}>
  20. <label>
  21. 文章:
  22. <textarea value={this.state.value} onChange={this.handleChange} />
  23. </label>
  24. <input type="submit" value="提交" />
  25. </form>
  26. );
  27. }
  28. }

C.select 标签

  1. class FlavorForm extends React.Component {
  2. constructor(props) {
  3. super(props);
  4. this.state = {value: 'coconut'};
  5. this.handleChange = this.handleChange.bind(this);
  6. this.handleSubmit = this.handleSubmit.bind(this);
  7. }
  8. handleChange(event) {
  9. this.setState({value: event.target.value});
  10. }
  11. handleSubmit(event) {
  12. alert('你喜欢的风味是: ' + this.state.value);
  13. event.preventDefault();
  14. }
  15. render() {
  16. return (
  17. <form onSubmit={this.handleSubmit}>
  18. <label>
  19. 选择你喜欢的风味:
  20. <select value={this.state.value} onChange={this.handleChange}>
  21. <option value="grapefruit">葡萄柚</option>
  22. <option value="lime">酸橙</option>
  23. <option value="coconut">椰子</option>
  24. <option value="mango">芒果</option>
  25. </select>
  26. </label>
  27. <input type="submit" value="提交" />
  28. </form>
  29. );
  30. }
  31. }

D.处理多个输入

需要处理多个 input 元素时,可以给每个元素添加 name 属性,并让处理函数根据 event.target.name 的值选择要执行的操作。

  1. class Reservation extends React.Component {
  2. constructor(props) {
  3. super(props);
  4. this.state = {
  5. isGoing: true,
  6. numberOfGuests: 2
  7. };
  8. this.handleInputChange = this.handleInputChange.bind(this);
  9. }
  10. handleInputChange(event) {
  11. const target = event.target;
  12. const value = target.type === 'checkbox' ? target.checked : target.value;
  13. const name = target.name;
  14. this.setState({
  15. [name]: value
  16. });
  17. }
  18. render() {
  19. return (
  20. <form>
  21. <label>
  22. 参与:
  23. <input
  24. name="isGoing"
  25. type="checkbox"
  26. checked={this.state.isGoing}
  27. onChange={this.handleInputChange} />
  28. </label>
  29. <br />
  30. <label>
  31. 来宾人数:
  32. <input
  33. name="numberOfGuests"
  34. type="number"
  35. value={this.state.numberOfGuests}
  36. onChange={this.handleInputChange} />
  37. </label>
  38. </form>
  39. );
  40. }
  41. }

E.受控输入空值

受控组件上指定 value 的 prop 可以防止用户更改输入。如果指定了 value,但输入仍可编辑,则可能是意外地将value 设置为 undefinednull
输入最初被锁定,但在短时间延迟后变为可编辑。

  1. ReactDOM.render(<input value="hi" />, mountNode);
  2. setTimeout(function() {
  3. ReactDOM.render(<input value={null} />, mountNode);
  4. }, 1000);

2、非受控组件

编写一个非受控组件,而不是为每个状态更新都编写数据处理函数,可以 使用 ref 来从 DOM 节点中获取表单数据。

  1. class NameForm extends React.Component {
  2. constructor(props) {
  3. super(props);
  4. this.handleSubmit = this.handleSubmit.bind(this);
  5. this.input = React.createRef();
  6. }
  7. handleSubmit(event) {
  8. alert('A name was submitted: ' + this.input.current.value);
  9. event.preventDefault();
  10. }
  11. render() {
  12. return (
  13. <form onSubmit={this.handleSubmit}>
  14. <label>
  15. Name:
  16. <input type="text" ref={this.input} />
  17. </label>
  18. <input type="submit" value="Submit" />
  19. </form>
  20. );
  21. }
  22. }

A.文件 input 标签

创建一个 DOM 节点的 ref 从而在提交表单时获取文件的信息。

  1. class FileInput extends React.Component {
  2. constructor(props) {
  3. super(props);
  4. this.handleSubmit = this.handleSubmit.bind(this);
  5. this.fileInput = React.createRef();
  6. }
  7. handleSubmit(event) {
  8. event.preventDefault();
  9. alert(
  10. `Selected file - ${
  11. this.fileInput.current.files[0].name
  12. }`
  13. );
  14. }
  15. render() {
  16. return (
  17. <form onSubmit={this.handleSubmit}>
  18. <label>
  19. Upload file:
  20. <input type="file" ref={this.fileInput} />
  21. </label>
  22. <br />
  23. <button type="submit">Submit</button>
  24. </form>
  25. );
  26. }
  27. }
  28. ReactDOM.render(
  29. <FileInput />,
  30. document.getElementById('root')
  31. );

3、为表单组件指定默认值

在 React 渲染生命周期时,表单元素上的 value 将会覆盖 DOM 节点中的值,在非受控组件中,你经常希望 React 能赋予组件一个初始值,但是不去控制后续的更新。 在这种情况下, 可以指定一个 defaultValue 属性,而不是 value
<input type="checkbox"><input type="radio"> 支持 defaultChecked <select><textarea> 支持 defaultValue

  1. render() {
  2. return (
  3. <form onSubmit={this.handleSubmit}>
  4. <label>
  5. Name:
  6. <input
  7. defaultValue="Bob"
  8. type="text"
  9. ref={this.input} />
  10. </label>
  11. <input type="submit" value="Submit" />
  12. </form>
  13. );
  14. }