React学习:表单(Forms)

受控组件(Controlled Components)

  • 在 HTML 中,表单元素如 < input>,< textarea> 和 < select> 表单元素通常保持自己的状态,并根据用户输入进行更新。
  • 在 React 中,可变状态一般保存在组件的 state(状态) 属性中,并且只能通过 setState() 更新。

我们可以通过使 React 的 state 成为 “单一数据源原则” 来结合这两个形式。然后渲染表单的 React 组件也可以控制在用户输入之后的行为。这种形式,其值由 React 控制的输入表单元素称为“受控组件”。


一、用value实现受控组件

总的来说,< input type=”text”>, < textarea> 和 < select> 工作方式都类似 —— 它们都接受一个 value 属性可以用来实现一个受控组件

1、< input type=”text”/>

看下面例子:
由于 value 属性设置在我们的表单元素上,显示的值总是 this.state.value,以满足 state 状态的同一数据理念。 handleChange 在每次敲击键盘时运行,以更新 React state(状态),显示的值将更新为用户的输入。

class NameForm extends React.Component {
  constructor(props){
    super(props);
    this.state = {value:''};
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this); 
  }
  handleChange(e){
    this.setState({
      value: e.target.value
    });
  }
  handleSubmit(e){
    alert('input value is : ' + this.state.value);
    e.preventDefault();
  }
  render(){
    return(
      <form onSubmit={this.handleSubmit}>
        <label>
          Name:
          <input type='text' onChange={this.handleChange} value={this.state.value}/>
        </label>
        <input type='submit' value='submit'/>
      </form>
    );
  }
}

ReactDOM.render(
  <NameForm />,
  document.getElementById('root')
);

输出:
这里写图片描述
输入信息,点击’submit’
这里写图片描述


对于受控组件来说,每一次 state(状态) 变化都会伴有相关联的处理函数。这使得可以直接修改或验证用户的输入。比如,如果我们希望强制 name 的输入都是大写字母,可以这样来写 handleChange 方法:

//效果:在键盘输入任意字母,input里显示出来的是大写字母
handleChange(e) {
  this.setState({value: e.target.value.toUpperCase()});
}

2、< textare/>

在 HTML 中,< textarea> 元素通过它的子节点定义了它的文本值:

<textarea>
  Hello there, this is some text in a text area
</textarea>

在 React 中,< textarea> 的赋值使用 value 属性替代。这样一来,表单中 < textarea> 的书写方式接近于单行文本输入框

例:

class EssayForm extends React.Component {
 constructor(props){
    super(props);
    this.state = {
      value:'Please write an essay'
    };
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this); 
  }
  handleChange(e){
    this.setState({
      value: e.target.value 
    });
  }
  handleSubmit(e){
    alert('input value is : ' + this.state.value);
    e.preventDefault();
  }
  render(){
    return(
      <form onSubmit={this.handleSubmit}>
        <label>
          message:<br/>
          <textarea type='text' onChange={this.handleChange} value={this.state.value} />
        </label>
        <input type='submit' value='submit'/>
      </form>
    );
  }
}

输出:
这里写图片描述
修改完值后,点击’submit’,会弹出
这里写图片描述


3、< select/>

在 HTML 中,< select> 创建了一个下拉列表。例如,这段 HTML 创建一个下拉列表:

<select>
  <option value="a">a</option>
  <option value="b">b</option>
  <option selected value="c">c</option>
  <option value="d">d</option>
</select>

在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(e){
        this.setState({
          value: e.target.value 
        });
      }
      handleSubmit(e){
        alert('you selected value is : ' + this.state.value);
        e.preventDefault();
      }
      render(){
        return(
          <form onSubmit={this.handleSubmit}>
            <label>
               Pick your favorite La Croix flavor:
              <select value={this.state.value} onChange={this.handleChange}>
                <option value="grapefruit">Grapefruit</option>
                <option value="lime">Lime</option>
                <option value="coconut">Coconut</option>
                <option value="mango">Mango</option>
              </select>
            </label>
            <input type='submit' value='submit'/>
          </form>
        );
      }
}

ReactDOM.render(
  <FlavorForm />,
  document.getElementById('root')
);

效果:(默认coconut被选中)
这里写图片描述
选择‘mango’,点击‘submit’后,
这里写图片描述

注意:
您可以将一个数组传递给 value 属性,允许你在 select 标签中选择多个选项:
<select multiple={true} value={['B', 'C']}>


二、file input 标签

在HTML中, < input type=”file”> 可以让用户从设备存储器中选择一个或多个文件上传到服务器,或者通过 JavaScript 使用 File API 操作。

<input type="file" />

在 React 中, 和一个普通的 < input /> 类似,但有一个重要的区别:它是只读的(您不能以编程方式设置值)。相反,你应该使用 File API 与文件进行交互。

以下示例显示了如何使用一个 ref 来访问提交处理程序中的文件:

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')
);

输出:
这里写图片描述
选择文件后,点击submit, 弹出文件名称
这里写图片描述


三、处理多个输入元素

当您需要处理多个受控的 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({
      [name]: value
    });
  }

  render() {
    return (
      <form>
        <label>
          Is going:
          <input
            name="isGoing"
            type="checkbox"
            checked={this.state.isGoing}
            onChange={this.handleInputChange} />
        </label>
        <br />
        <label>
          Number of guests:
          <input
            name="numberOfGuests"
            type="number"
            value={this.state.numberOfGuests}
            onChange={this.handleInputChange} />
        </label>
      </form>
    );
  }
}

ReactDOM.render(
  <Reservation />,
  document.getElementById('root')
);

输出效果:点击我

注意我们如何使用ES6计算的 属性名称语法 来更新与给定输入名称相对应的 state(状态) 键:

this.setState({
  [name]: value
});

这段代码等价于 ES5 代码:

var partialState = {};
partialState[name] = value;
this.setState(partialState);

四、受控 Input 组件的 null 值

官方文档是这么说的
这里写图片描述
其实意思就是

下面这段代码,不能编辑 input的值

ReactDOM.render(
    <input type='text' value="hi" />, 
    document.getElementById('root')
);

但下面这段代码 可以编辑 input里的值

ReactDOM.render(
      <input type='text' value={null} />, 
      document.getElementById('root')
 );

受控组件的替代方案:
有时使用受控组件有些乏味,因为你需要为每一个可更改的数据提供事件处理器,并通过 React 组件管理所有输入状态。当你将已经存在的代码转换为 React 时,或将 React 应用程序与非 React 库集成时,这可能变得特别烦人。在这些情况下,您可能需要使用不受控的组件,用于实现输入表单的替代技术。

猜你喜欢

转载自blog.csdn.net/b954960630/article/details/79951209