React 学习笔记(3)this指向问题与表单处理

本文探讨了React中事件绑定时this指向的问题,介绍了使用箭头函数、Function.prototype.bind()以及class实例方法来确保正确的上下文。接着详细讲解了受控组件的概念,如何通过state管理和变更表单元素的值,以及优化多表单元素事件处理的方法。最后提到了非受控组件的使用,但推荐使用受控组件以更好地管理表单数据。
摘要由CSDN通过智能技术生成

事件绑定中的this指向

  • 1、箭头函数
    利用箭头函数自身不绑定this的特点
    render()方法中的this为组件实例,可以获取到setState()
render(){

//箭头函数的this并不属于箭头函数自身,指向外部环境render()方法,render()的this指向当前实例

return (
<div>

<h1>计数器:{this.state.count}</h1>
<button onClick = {()=>{this.onIncrement()}}>增加</button>
</div>
)}
  • 2、Function.prototype.bind()

利用ES5的bind方法,将事件处理程序中的this与组件实例绑定到一起
bind()方法创建一个新的函数,在bind被调用时,这个新函数的this被指定为bind()的第一个参数

  constructor(){
        super()
        //初始化state
        this.state = {
            count:0
        }
        this.onIncrement = this.onIncrement.bind(this)
    }

<h1>计数器:{this.state.count}</h1>
<button onClick = {this.onIncrement}>增加</button>

先调用construtor函数,再调用render函数,render函数里的this.onIncrement是被赋值之后的函数

3、class的实例方法—(推荐使用)
利用箭头函数形式的class实例方法
注意:该语法是实验性语法,脚手架中配置了babel,可以直接使用。

    //事件处理程序
    handleClick=()=>{
        alert('事件已经触发!!')
    }
    onIncrement=()=>{
        this.setState({
            count: this.state.count+1
        })
    }
    

表单处理

受控组件

  • HTML的表单元素是可输入的,也就是有自己的可变状态
  • React中可变状态通常保存在state中,并且只能通过setState()方法来进行修改
  • React将state与表单元素值value值绑定在一起,由state值控制表单元素的值
  • 受控组件:值受到React控制的表单元素
state = {txt:''}
<input type = "text" value = {this.state.txt} onChange = {this.handleChange}/>

步骤
1、在state中添加一个状态,作为表单元素的value值
2、给表单元素绑定change事件,将表单元素的值设置为state的值(控制表单元素值的变化)
文本框、富文本框,下拉框,复选框的使用示例

文本框、富文本框、下拉框操作value属性
复选框操作checked属性

import React, { Component } from 'react'

export default class Control extends Component {
    state = {
        txt:'',
        content:'',
        city:'',
        isChecked:false
    }
    handleChange = e=>{
        this.setState({
            txt:e.target.value
        })
    }
    handleContent = e=>{
        this.setState({
            content:e.target.value
        })
    }
    handleCity = e=>{
        this.setState({
            city:e.target.value
        })
    }
    handleChecked = e =>{
        this.setState({
            isChecked:e.target.checked
        })
    }
    render() {
        return (
            <div>
                {/* 文本框 */}
                <input type = "text" value = {this.state.txt} onChange = {this.handleChange}/>
                <h1>{this.state.txt}</h1>
                <br />
                {/* 富文本框 */}
                <textarea value = {this.state.content} onChange = {this.handleContent}></textarea>
                <h1>{this.state.content}</h1>
                <br />
                {/* 下拉框 */}
                <select value = {this.state.city} onChange = {this.handleCity}>
                    <option value = "sh">上海</option>
                    <option value = "bj">北京</option>
                    <option value = "gz">广州</option>
                </select>
                <h1>{this.state.city}</h1>
                {/* 复选框 */}
                <input type = "checkbox" checked = {this.state.isChecked} onChange = {this.handleChecked}/>
                <h1> {this.state.isChecked}</h1>
            </div>
        )
    }
}

多表单元素优化

问题:每个表单元素都有独立的事件处理程序,太繁琐

优化:使用一个事件处理程序同时处理多个表单元素

优化步骤

  • 给表单元素添加name属性,名称与state相同,用于区分其他的表单元素,更新状态
  • 根据表单元素类型获取对应的值,value/checked属性
    const value = target.type===‘checkbox’ ? target.checked : target.value
  • 在change事件事件处理程序中[name]修改对应的state
    const name = target.name this.setState({[name] : value})
import React, { Component } from 'react'

export default class ControlMajor extends Component {
    state = {
        txt:'',
        content:'',
        city:'',
        isChecked:false
    }
    handleForm = e=>{
        //获取当前DOM对象
        const target = e.target
        //根据类型获取值
        const value  = target.type==='checkbox' ? target.checked : target.value
        //获取name 
        const name = target.name
        this.setState({
            [name] : value
        })
    }
   
    render() {
        return (
            <div>
                {/* 文本框 */}
                <input type = "text" name = 'txt' value = {this.state.txt} onChange = {this.handleForm}/>
                <h1>{this.state.txt}</h1>
                <br />
                {/* 富文本框 */}
                <textarea name = 'content' value = {this.state.content} onChange = {this.handleForm}></textarea>
                <h1>{this.state.content}</h1>
                <br />
                {/* 下拉框 */}
                <select name = 'city' value = {this.state.city} onChange = {this.handleForm}>
                    <option value = "sh">上海</option>
                    <option value = "bj">北京</option>
                    <option value = "gz">广州</option>
                </select>
                <h1>{this.state.city}</h1>
                {/* 复选框 */}
                <input type = "checkbox" name = 'isChecked' checked = {this.state.isChecked} onChange = {this.handleForm}/>
                <h1> {this.state.isChecked}</h1>
            </div>
        )
    }
}

非受控组件(不推荐)
1、调用React.createRef()创建一个ref对象
2、将创建好的ref对象添加到文本框中
3、同股票ref对象获取文本框的值
React基础总结

  • 组件的两种创建方式:函数组件与类组件
  • 无状态(函数)组件,负责静态结构展示
  • 有状态组件,负责更新UI,让页面动起来
  • 绑定事件注意this指向问题
  • 推荐使用受控组件处理表单
  • 完全利用JS的语言特性创建组件,这是React的思想

完成小练习,写了一个组件
渲染评论列表(列表渲染)
没有评论时渲染:暂无评论(条件渲染),
获取评论信息(受控组件)
发表评论,更新评论列表(setState())
实现表单列表渲染,条件渲染,受控组件,,边界判断

import React, { Component } from 'react'
import '../CSS/test1.css'
export default class Test1 extends Component {
    state = {
        //初始化状态
        comments: [
            { id: 1, name: 'jack', content: '沙发!!' },
            { id: 2, name: 'rose', content: '板凳!!' },
            { id: 3, name: 'tom', content: '楼主好人' }
        ],
        userName:'',//评论人
        userContent:''//评论信息
    }
    //渲染评论列表
    renderList(){
        return this.state.comments.length === 0 ?
                (
                    <div className="no-content">暂无评论,快去评论吧~</div>
                ) :
                (
                    <ul>
                        {this.state.comments.map(item =>
                            <li key={item.id}>
                                <h3>{item.name}</h3>
                                <p>{item.content}</p>
                            </li>
                        )}
                    </ul>
                )
    }
    handleName = e=>{
        this.setState({
            userName:e.target.value
        })
    }
    handleContent = e=>{
        this.setState({
            userContent:e.target.value
        })
    }
    addContent = ()=>{
        const {comments,userName,userContent} = this.state
        //非空校验
        if(userName.trim()===''||userContent.trim()===''){
            alert("请输入评论人与评论信息")
            return 
        }

        const newComments = [{
            id:Math.random(),
            name:userName,
            content:userContent
        },...comments]
        console.log(newComments)
        this.setState ({
            comments:newComments,
            //清空文本框
            userName:'',
            userContent:''
        })

        
    }
    render() {
        return (
            <div className="app">
                <div>
                    <input className="user" type="text" placeholder="请输入评论人"  value = {this.state.userName} onChange = {this.handleName}/>
                    <br />
                    <textarea
                        className="content"
                        cols="30"
                        rows="10"
                        placeholder="请输入评论内容"
                        value = {this.state.userContent}
                        onChange = {this.handleContent}
                    />
                    <br />
                    <button onClick = {this.addContent}>发表评论</button>
                </div>
                {/* 条件渲染,通过数据长度判断 */}
                {this.renderList()}
                {/* {this.state.comments.length === 0 ?
                    (
                        <div className="no-content">暂无评论,快去评论吧~</div>
                    ) :
                    (
                        <ul>
                            {this.state.comments.map(item =>
                                <li key={item.id}>
                                    <h3>{item.name}</h3>
                                    <p>{item.content}</p>
                                </li>
                            )}
                        </ul>
                    )
                } */}


            </div>
        )
    }
}

.app{
    border: 1px solid;
    width: 300px;
    padding: 10px;
    background-color: cyan;
}
.user{
    width: 240px;
    margin-top: 10px;
}
.content{
    margin-top: 10px;
    margin-bottom: 10px;
}
.no-content{
    margin-top: 10px;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值