### 彪哥

爱好前端

- 核心概念

  - JSX简介
  - 元素渲染
  - 组件&Props
  - State&生命周期
  - 事件处理
  - 条件渲染
  - 列表&Key
  - 表单
    - 受控组件（双向数据绑定）
    - textarea 标签（使用value定义值）
    - select 标签 （value代替选中属性）
      - select多选
      - 小总结
    - 文件 input 标签 （非受控组件）
    - 处理多个输入
    - 受控输入空值
    - 受控组件的替代品 (非受控组件)
    - 成熟的解决方案
  - 状态提升 (共享状态)
  - 组合vs继承
  - React哲学

- 高级指引

- Hook

- 案例演示

- 《React》笔记
- 核心概念

heBody
2021-03-24
目录

# 表单

# # 08. 表单

## # 受控组件（双向数据绑定）

在 HTML 中，表单元素（如`<input>`、 `<textarea>` 和 `<select>`）通常自己维护 state，并根据用户输入进行更新。而在 React 中，可变状态（mutable state）通常保存在组件的 state 属性中，并且只能通过使用 `setState()`
(opens new window)来更新。

我们可以把两者结合起来，使 React 的 state 成为“唯一数据源”。渲染表单的 React 组件还控制着用户输入过程中表单发生的操作。被 React 以这种方式控制取值的表单输入元素就叫做“受控组件”。

例如，如果我们想让前一个示例在提交时打印出名称，我们可以将表单写为受控组件：

    class Name extends React.Component {
      constructor(props){
        super(props);
        this.state = {value: ''}

        this.handleChange = this.handleChange.bind(this)
        this.handleSubmit = this.handleSubmit.bind(this)
      }

      handleChange(event){
        this.setState({value: event.target.value})
      }

      handleSubmit(event){
        alert(this.state.value)
        event.preventDefault();
      }

      render(){
        return(
         <form onSubmit={this.handleSubmit}>
            <label>
              名字:
              <input type="text" value={this.state.value} onChange={this.handleChange} />
            </label>
            <input type="submit" value="提交" />
          </form>
        )
      }
    }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

> 类似于vue中的双向绑定，v-model

## # textarea 标签（使用value定义值）

在 HTML 中, `<textarea>` 元素通过其子元素定义其文本:

    <textarea>
      你好， 这是在 text area 里的文本
    </textarea>

1
2
3

在 React 中，`<textarea>` 使用 `value` 属性赋值。这样，可以使得使用 `<textarea>` 的表单和使用单行 input 的表单非常类似：

    class EssayForm extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          value: '请撰写一篇关于你喜欢的 DOM 元素的文章.'
        };
        this.handleChange = this.handleChange.bind(this);
        this.handleSubmit = this.handleSubmit.bind(this);
      }

      handleChange(event) {
        this.setState({value: event.target.value});
      }
      handleSubmit(event) {
        alert('提交的文章: ' + this.state.value);
        event.preventDefault();
      }

      render() {
        return (
          <form onSubmit={this.handleSubmit}>
            <label>
              文章:
              <textarea value={this.state.value} onChange={this.handleChange} />        </label>
            <input type="submit" value="提交" />
          </form>
        );
      }
    }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

注意，`this.state.value` 初始化于构造函数中，因此文本区域默认有初值

## # select 标签 （value代替选中属性）

React 在根 `select` 标签上使用 `value` 属性代替`option`元素上的`selected` 属性（选中属性）

在 HTML 中，`<select>` 创建下拉列表标签。例如，如下 HTML 创建了水果相关的下拉列表：

    <select>
      <option value="grapefruit">葡萄柚</option>
      <option value="lime">酸橙</option>
      <option selected value="coconut">椰子</option>
      <option value="mango">芒果</option>
    </select>

1
2
3
4
5
6

请注意，由于 `selected` 属性的缘故，椰子选项默认被选中。React 并不会使用 `selected` 属性，而是在根 `select` 标签上使用 `value` 属性。这在受控组件中更便捷，因为您只需要在根标签中更新它。例如：

    class FlavorForm extends React.Component {
      constructor(props) {
        super(props);
        this.state = {value: 'coconut'};

        this.handleChange = this.handleChange.bind(this);
        this.handleSubmit = this.handleSubmit.bind(this);
      }

      handleChange(event) {
        this.setState({value: event.target.value});
      }

      handleSubmit(event) {
        alert('你喜欢的风味是: ' + this.state.value);
        event.preventDefault();
      }

      render() {
        return (
          <form onSubmit={this.handleSubmit}>
            <label>
              选择你喜欢的风味:
              <select value={this.state.value} onChange={this.handleChange}>
                <option value="grapefruit">葡萄柚</option>
                <option value="lime">酸橙</option>
                <option value="coconut">椰子</option>
                <option value="mango">芒果</option>
              </select>
            </label>
            <input type="submit" value="提交" />
          </form>
        );
      }
    }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

### # select多选

你可以将数组传递到 `value` 属性中，以支持在 `select` 标签中选择多个选项：

    <select multiple={true} value={['B', 'C']}>

1

### # 小总结

总的来说，这使得 `<input type="text">`, `<textarea>` 和 `<select>` 之类的标签都非常相似—它们都接受一个 `value` 属性，你可以使用它来实现受控组件。

## # 文件 input 标签 （非受控组件）

在 HTML 中，`<input type="file">` 允许用户从存储设备中选择一个或多个文件，将其上传到服务器，或通过使用 JavaScript 的 File API
(opens new window) 进行控制。

    <input type="file" />

1

因为它的 value 只读，所以它是 React 中的一个非受控组件。将与其他非受控组件在后续文档中
(opens new window)一起讨论。

## # 处理多个输入

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

    class Reservation extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          isGoing: true,
          numberOfGuests: 2
        };

        this.handleInputChange = this.handleInputChange.bind(this);
      }

      handleInputChange(event) {
        const target = event.target;
        const value = target.type === 'checkbox' ? target.checked : target.value;
        const name = target.name;

        this.setState({
          // ES6 计算属性名称
          [name]: value
        });
      }

      render() {
        return (
          <form>
            <label>
              参与:
              <input
                name="isGoing"
                type="checkbox"
                checked={this.state.isGoing}
                onChange={this.handleInputChange} />
            </label>
            <br />
            <label>
              来宾人数:
              <input
                name="numberOfGuests"
                type="number"
                value={this.state.numberOfGuests}
                onChange={this.handleInputChange} />
            </label>
          </form>
        );
      }
    }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

## # 受控输入空值

在受控组件
(opens new window)上指定 value 的 prop 会阻止用户更改输入。如果你指定了 `value`，但输入仍可编辑，则可能是你意外地将`value` 设置为 `undefined` 或 `null`。

下面的代码演示了这一点。（输入最初被锁定，但在短时间延迟后变为可编辑。）

    ReactDOM.render(<input value="hi" />, mountNode);

    setTimeout(function() {
      ReactDOM.render(<input value={null} />, mountNode);
    }, 1000);

1
2
3
4
5

## # 受控组件的替代品 (非受控组件)

有时使用受控组件会很麻烦，因为你需要为数据变化的每种方式都编写事件处理函数，并通过一个 React 组件传递所有的输入 state。当你将之前的代码库转换为 React 或将 React 应用程序与非 React 库集成时，这可能会令人厌烦。在这些情况下，你可能希望使用非受控组件
(opens new window), 这是实现输入表单的另一种方式。

## # 成熟的解决方案

如果你想寻找包含验证、追踪访问字段以及处理表单提交的完整解决方案，使用 Formik
(opens new window) 是不错的选择。然而，它也是建立在受控组件和管理 state 的基础之上 —— 所以不要忽视学习它们。

编辑
(opens new window)
#React
上次更新: 2022/12/14, 19:36:42
列表&Key
状态提升 (共享状态)

← 列表&Key 状态提升 (共享状态)→

最近更新

  01
Git修改分支名
08-11

  02
CSS给table的tbody添加滚动条
06-29

  03
我做了一个手写春联小网页，祝大家虎年暴富 原创
01-28

更多文章>

Copyright © 2016-2022 Hesb | MIT License

- 跟随系统
- 浅色模式
- 深色模式
- 阅读模式