React 表单受控组件(双向绑定数据)、非受控组件、React组件综合案例、表单处理

一、受控组件

相当于数据的双向绑定,理解为vue中的v-model。将input的值存入state中。

  • HTML中的表单元素是可输入的,也就是有自己的可变状态
  • 而React中可变状态通常保存在state中,并且只能通过setState() 方法来修改
  • React将state与表单元素值value绑定在一起,有state的值来控制表单元素的值
  • 受控组件:值受到react控制的表单元素

在这里插入图片描述

使用步骤

  • 在state中添加一个状态,作为表单元素的value值
  • 给表单元素绑定change事件,将表单元素的值设置为state的值

示例demo

class App extends React.Component {
    constructor(){
        super()
        this.inputChange = this.inputChange.bind(this)
        //bind使inputChange里的this 指向class类的this
    }
    state = {
        txt : ''
    }
    inputChange(e){
       this.setState({
           txt: e.target.value
       })
    }
    render(){
        console.log(this.state);
        
        return (
            <div>
                {/* 把state的值设置给输入框的value,绑定change事件,这样用户在输入内容的时候调用相应函数,在函数里面把当前设置的值赋值给state,从而达到数据的统一 */}
                <input type="text" value={this.state.txt} onChange={this.inputChange}/>
            </div>
        )
    }
}
ReactDOM.render(<App />,document.getElementById('root'))

在这里插入图片描述
在这里插入图片描述

多表单元素示例

在这里插入图片描述
在这里插入图片描述

多表单元素优化

  • 问题:每个表单元素都有一个单独的事件处理函数,这样太繁琐
  • 优化:使用一个事件处理程序同时处理多个表单元素

步骤

  • 给表单元素添加name属性(用来区分是哪一个表单),名称与state相同(用来更新数据的)
  • 根据表单内容来获取对应值
  • 在change事件处理程序中通过 [name] 来修改对应的state
inputChange(e){
   let target = e.target;
   let value = target.type == 'checkbox' ? target.checked : target.value;
   this.setState({
       [e.target.name]: value
   })
}
<input type="text" value={this.state.txt} name="txt" onChange={this.inputChange}/>
<input type="checkbox" value={this.state.isChecked} name="isChecked" onChange={this.inputChange}/>

在这里插入图片描述

二、非受控组件 (了解)

  • 说明:借助于ref,使用元素DOM方式获取表单元素值
  • ref的作用:获取DOM或者组件

使用步骤

  • 调用 React.createRef() 方法创建ref对象
  • 将创建好的 ref 对象添加到文本框中
  • 通过ref对象获取到文本框的值
class App extends React.Component {
    constructor(){
        super()
        
        //创建 ref
        this.txtRef = React.createRef()
    }
    // 获取文本框的值
    getTxt =() => {
        console.log(this.txtRef.current.value)
    }
    render(){
        return (
          <div>
            <input type ="text" ref={this.txtRef} />
            <button onClick ={this.getTxt}>获取值</button>
          </div>
        )
    }
}

在这里插入图片描述

三、React组件综合案例

需求分析

  • 渲染评论列表(列表渲染)
  • 没有评论数据时渲染:暂无评论(条件渲染)
  • 获取评论信息,包括评论人和评论内容(受控组件)
  • 发表评论,更新评论列表(setState()

在这里插入图片描述

class App extends React.Component {
  state = {
    userName: '',
    userContent: '',
    comments: [
      { id: 1, name: 'jack', content: '沙发!!!' },
      { id: 2, name: 'rose', content: '板凳~' },
      { id: 3, name: 'tom', content: '楼主好人' }
    ]
  }

  // 渲染暂无评论
  renderList() {
    return this.state.comments.length > 0 ? (
      <ul> {
        this.state.comments.map(item => {
          return (
            <li key={item.id}>
              <h3>{item.name}</h3>
              <p>{item.content}</p>
            </li>
          )
        })
      }
      </ul>)
      : (<div className="no-comment">暂无评论,快去评论吧~</div>)
  }

  // 双向绑定表单
  handleChange = e => {
    this.setState({
      [e.target.name]: e.target.value
    })
  }

  // 绑定点击事件
  handleClick = e => {
    //拿到用户输入的内容
    let { userName, userContent } = this.state
    if (userName.trim === '' || userContent.trim() === '') {
      alert('请输入内容')
      return
    }

    // 利用数组拓展运算符来进行数据的拼接,把用户输入的存放在数组的第一个位置
    let newComments = [
      {
        id: this.state.comments.length + 1,
        name: userName,
        content: userContent
      }, ...this.state.comments
    ]

    this.setState(
      {
        comments: newComments,
        userName: '',
        userContent: ''
      }
    )
  }

  render() {
    return (
      <div className='box'>
        <input type="text" placeholder='请输入评论人' className='user' name="userName" value={this.state.userName} onChange={this.handleChange}></input>
        <textarea className='content' name="userContent" value={this.state.userContent} onChange={this.handleChange}></textarea>
        <button onClick={this.handleClick}>发表评论</button>
        <div style={{ "height": "200px", "width": "100%", 'overflow': 'scroll' }}>
          {this.renderList()}
        </div>

      </div>

    )
  }

}

createRoot(document.getElementById('root')).render(<App></App>)

index.css

.box {

  display:  flex;

  flex-direction: column;

  justify-content: space-between;

  box-sizing: border-box;
  
  padding: 10px;

  width: 300px;
  height: 500px;

  border: 1px solid grey;

  margin: 0 auto;

}

.user{
  width: 100%;
}

.content{

  width: 100%;
  height: 40%;

}

四、表单处理

获取用户所填写的内容我们必须要监听表单onChange事件,在表单项发生变化时获取其中的内容,在响应函数中通过事件对象的target.value来获取用户填写的内容

const nameChangeHandler= e => {
     //e.target.value 表示当前用户输入的值
};

然后我们再将该函数设置为input元素的onChange事件的响应函数:

<div>
    用户名 <input type="text" onChange={nameChangeHandler}/>
</div>

这样一来当用户输入内容时,nameChangeHandler就会被触发,从而通过e.target.value来获取用户输入的值。通常我们还会为表单项创建一个state用来存储值:

const [inputName, setInputName] = useState(''); 
const nameChangeHandler = e => {
    //e.target.value 表示当前用户输入的值
    setInputName(e.target.value);
 };

上例中用户名存储到了变量inputName中,inputName也会设置为对应表单项的value属性值,这样一来当inputName发生变化时,表单项中的内容也会随之改变:

<div>
    用户名 <input type="text" onChange={nameChangeHandler} value={inputName}/>
</div>

当用户输入内容后会触发onChange事件从而调用nameChangeHandler函数,在函数内部调用了setInputName设置了用户输入的用户名。
在表单中输入内容会影响到state的值,同时当我们修改state的值时,由于表单项的value属性值指向了state,表单也会随state值一起改变。这种绑定方式我们称为双向绑定,即表单会改变state,state也可以改变表单,在开发中使用双向绑定的表单项是最佳实践。

那么表单的提交要如何处理呢?表单提交同样需要通过事件来处理,提交表单的事件通过form标签的onSubmit事件来绑定,处理表单的方式因情况而已,但是一定要注意,必须要取消默认行为,否则会触发表单的默认提交行为:

const formSubmitHandler = e => {
    e.preventDefault();
    /*
     * username : inputName
     * password : pwdInput
     * email : inputEmail     
     * */
};

为表单绑定事件:

<form onSubmit={formSubmitHandler}>
......
</form>

如此我们便有了一个简单的表单案例,完整代码如下:
在这里插入图片描述
在这里插入图片描述
在这个案例中,表单的所有功能包括输入、显示、提交全部都由React所处理。这种表单项在React中被称为受控组件,即表单项受React控制。当然也存在有不受控组件,但那种组件使用机会少且需要通过原生DOM去操作表单,并不建议使用,所以这里便不再赘述了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值