欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

React — 从表单认识的受控组件

程序员文章站 2022-03-12 21:50:02
表单在React里,HTML表单元素的工作方式和其他的DOM的元素有些不用,这是因为表单元素通常会保持一些内部的state,例如这个纯html表单直接收一个名称:

表单

在React里,HTML表单元素的工作方式和其他的DOM的元素有些不用,这是因为表单元素通常会保持一些内部的state,例如这个纯html表单直接收一个名称:

    <form>
        <label>
            名称:
            <input type="text" name="name"/>
        </label>
         <input type="submit" value="提交" />
    </form>

此表单具有默认的HTML表单行为,即在用户提交表单后浏览到新页面。
如果你在React中执行相同的代码,他依然有效,但是大多数情况下,使用JavaScript函数可以很方便的处理表单的提交,同时还可以访问用户填写的表单数据。实现这种效果的标准方式是使用"受控组件"。

受控组件

在HTML中,表单元素(如,和)之类的表单元素通常自己维护state,并根据用户输入进行更新。而在React中,可变状态通常保存在组件的state中,并且只能通过setState来更新。

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

假如,如果我们想让前一个实例在提交时候打印出名称,我么可以将表单写成受控组件:

class NameForm extends React.Component {
    constructor(props) {
        super(props)
        this.state = {
            value: props.value ? props.value : ""
        }


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

    handleSubmit = (event) => {
        alert('提交的名字: ' + this.state.value);
        event.preventDefault();
    }

    render(){

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

ReactDOM.render(<NameForm/>,document.querySelector('#root'))

由于在表单元素上设置了value属性,因此显示的值将始终为this.state.value,这使得React的state成为唯一数据源。由于handleChange在每次按键时都会执行并更新React的state,因此显示的值将随着用户输入而更新。

对于受控组件来说,输入的值始终由React的state驱动。你也可以将value传递给其他UI元素,或者通过其他时间处理函数重置,但是意味着你需要编写更多的代码。

textarea 标签

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

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

而在React中,使用value属性代替。这样,可以使得使用<textarea>的表单和使用单行的input的表单非常类似:

class TextareaControl extends React.Component {
    constructor(props) {
        super(props)
        this.state = {
            value: props.value ? props.value : ""
        }
    }
    handleSubmit = () => {
        alert(this.state.value)
    }
    handleChange = (ev) => {
        this.setState({
            value: ev.target.value
        })
    }
    render () {
        return (
            <form onSubmit={this.handleSubmit}>
                <div>{this.state.value}</div>
                <label>
                    名字:
                <textarea type="text" value={this.state.value} onChange={this.handleChange} />
                </label>
                <input type="submit" value="提交" />
            </form>
        )
    }
}

ReactDOM.render(<TextareaControl />, document.querySelector('#root'))

select标签

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

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

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

class SelectControl extends TextareaControl {
    constructor(props) {
        super(props)
    }

    render () {
        return (
            <form onSubmit={this.handleSubmit}>
                <label>
                    选择你喜欢的风味:{this.state.value}
              <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>
        );
    }
}

ReactDOM.render(<SelectControl />, document.querySelector('#root'))

总的来说,这使得 , 和 之类的标签都非常相似—它们都接受一个 value 属性,你可以使用它来实现受控组件

文件input标签

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

<input type="file">

因为它的value是只读,所以它是React中的一个非受控组件。

处理多个输入

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

class Reservation extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            isGoing: true,
            numberOfGuests: 2
        }
    }
    handleInputChange = (ev) => {
        const target = ev.target;
        const value = target.name === 'isGoing' ? target.checked : target.value;
        const name = target.name;
        this.setState({
            [name]: value
        })
    }
    render () {
        return (
            <form>
                {JSON.stringify(this.state)}
                <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>
        )
    }
}
ReactDOM.render( <Reservation />,document.querySelector("#root"))

这里使用了 ES6 计算属性名称的语法更新给定输入名称对应的 state 值:
等同于ES5的

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

另外由于setState自动将部分的state合并到当前state,只需要调用它更改部分的state即可。

受控输入空值

在受控组件上指定value的prop会阻止用户更改输入。如果你执行了value,单输入仍可编辑,则可能是你意外地将value设置成了undefined或null。

ReactDOM.render( <input value="hi"  onChange={()=>{}}/>,document.querySelector("#root"))
setTimeout(function() {
    ReactDOM.render(<input value={null} onChange={()=>{}} />, document.querySelector("#root"));
  }, 1000);

受控组件的代替品

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

本文地址:https://blog.csdn.net/qq_41914181/article/details/111146540